diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-12-27 15:43:48 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-02-05 08:39:12 -0500 |
commit | 2bfb50924c7e92362ac937aef2ab56bc7bd3ca52 (patch) | |
tree | 26518070c19eb9cfb38ab48cda31fe16c1235433 | |
parent | c9f7a8ab7792b48259af6e94706a5d02dd74caef (diff) |
iwlwifi: use threaded interrupt handler
With new transports coming up, move to threaded
interrupt handling now. This has the advantage
that we can use the same locking scheme with all
different transports we may need to implement.
Note that the TX path obviously still runs in a
tasklet, so some spin_lock() calls need to change
to spin_lock_bh() calls to properly lock out the
TX path.
In my test on a Calpella platform this has no
impact on throughput or latency.
Also add lockdep annotations to avoid lockups due
to catch sending synchronous commands or using
locks that connect with them from the irq thread.
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/rx.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/sta.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/tx.c | 16 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-op-mode.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.h | 29 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/rx.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/tx.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/internal.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/rx.c | 40 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/trans.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/tx.c | 8 |
11 files changed, 85 insertions, 52 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index e8d5b90abf5c..a4eed2055fdb 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c | |||
@@ -790,7 +790,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
790 | 790 | ||
791 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | 791 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); |
792 | 792 | ||
793 | ieee80211_rx(priv->hw, skb); | 793 | ieee80211_rx_ni(priv->hw, skb); |
794 | } | 794 | } |
795 | 795 | ||
796 | static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | 796 | static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) |
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index ab768045696b..2d33760a9dc2 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
@@ -77,7 +77,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, | |||
77 | IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", | 77 | IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", |
78 | sta_id); | 78 | sta_id); |
79 | 79 | ||
80 | spin_lock(&priv->sta_lock); | 80 | spin_lock_bh(&priv->sta_lock); |
81 | 81 | ||
82 | switch (add_sta_resp->status) { | 82 | switch (add_sta_resp->status) { |
83 | case ADD_STA_SUCCESS_MSK: | 83 | case ADD_STA_SUCCESS_MSK: |
@@ -119,7 +119,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, | |||
119 | priv->stations[sta_id].sta.mode == | 119 | priv->stations[sta_id].sta.mode == |
120 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", | 120 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", |
121 | addsta->sta.addr); | 121 | addsta->sta.addr); |
122 | spin_unlock(&priv->sta_lock); | 122 | spin_unlock_bh(&priv->sta_lock); |
123 | 123 | ||
124 | return ret; | 124 | return ret; |
125 | } | 125 | } |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 7b0550d35a91..4ece5ea81b86 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -1117,7 +1117,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1117 | sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> | 1117 | sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> |
1118 | IWLAGN_TX_RES_RA_POS; | 1118 | IWLAGN_TX_RES_RA_POS; |
1119 | 1119 | ||
1120 | spin_lock(&priv->sta_lock); | 1120 | spin_lock_bh(&priv->sta_lock); |
1121 | 1121 | ||
1122 | if (is_agg) | 1122 | if (is_agg) |
1123 | iwl_rx_reply_tx_agg(priv, tx_resp); | 1123 | iwl_rx_reply_tx_agg(priv, tx_resp); |
@@ -1239,11 +1239,11 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1239 | le16_to_cpu(tx_resp->seq_ctl)); | 1239 | le16_to_cpu(tx_resp->seq_ctl)); |
1240 | 1240 | ||
1241 | iwl_check_abort_status(priv, tx_resp->frame_count, status); | 1241 | iwl_check_abort_status(priv, tx_resp->frame_count, status); |
1242 | spin_unlock(&priv->sta_lock); | 1242 | spin_unlock_bh(&priv->sta_lock); |
1243 | 1243 | ||
1244 | while (!skb_queue_empty(&skbs)) { | 1244 | while (!skb_queue_empty(&skbs)) { |
1245 | skb = __skb_dequeue(&skbs); | 1245 | skb = __skb_dequeue(&skbs); |
1246 | ieee80211_tx_status(priv->hw, skb); | 1246 | ieee80211_tx_status_ni(priv->hw, skb); |
1247 | } | 1247 | } |
1248 | 1248 | ||
1249 | if (is_offchannel_skb) | 1249 | if (is_offchannel_skb) |
@@ -1290,12 +1290,12 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1290 | tid = ba_resp->tid; | 1290 | tid = ba_resp->tid; |
1291 | agg = &priv->tid_data[sta_id][tid].agg; | 1291 | agg = &priv->tid_data[sta_id][tid].agg; |
1292 | 1292 | ||
1293 | spin_lock(&priv->sta_lock); | 1293 | spin_lock_bh(&priv->sta_lock); |
1294 | 1294 | ||
1295 | if (unlikely(!agg->wait_for_ba)) { | 1295 | if (unlikely(!agg->wait_for_ba)) { |
1296 | if (unlikely(ba_resp->bitmap)) | 1296 | if (unlikely(ba_resp->bitmap)) |
1297 | IWL_ERR(priv, "Received BA when not expected\n"); | 1297 | IWL_ERR(priv, "Received BA when not expected\n"); |
1298 | spin_unlock(&priv->sta_lock); | 1298 | spin_unlock_bh(&priv->sta_lock); |
1299 | return 0; | 1299 | return 0; |
1300 | } | 1300 | } |
1301 | 1301 | ||
@@ -1309,7 +1309,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1309 | IWL_DEBUG_TX_QUEUES(priv, | 1309 | IWL_DEBUG_TX_QUEUES(priv, |
1310 | "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n", | 1310 | "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n", |
1311 | scd_flow, sta_id, tid, agg->txq_id); | 1311 | scd_flow, sta_id, tid, agg->txq_id); |
1312 | spin_unlock(&priv->sta_lock); | 1312 | spin_unlock_bh(&priv->sta_lock); |
1313 | return 0; | 1313 | return 0; |
1314 | } | 1314 | } |
1315 | 1315 | ||
@@ -1378,11 +1378,11 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1378 | } | 1378 | } |
1379 | } | 1379 | } |
1380 | 1380 | ||
1381 | spin_unlock(&priv->sta_lock); | 1381 | spin_unlock_bh(&priv->sta_lock); |
1382 | 1382 | ||
1383 | while (!skb_queue_empty(&reclaimed_skbs)) { | 1383 | while (!skb_queue_empty(&reclaimed_skbs)) { |
1384 | skb = __skb_dequeue(&reclaimed_skbs); | 1384 | skb = __skb_dequeue(&reclaimed_skbs); |
1385 | ieee80211_tx_status(priv->hw, skb); | 1385 | ieee80211_tx_status_ni(priv->hw, skb); |
1386 | } | 1386 | } |
1387 | 1387 | ||
1388 | return 0; | 1388 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index dc792584f401..4a680019e117 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h | |||
@@ -113,13 +113,13 @@ struct iwl_cfg; | |||
113 | * May sleep | 113 | * May sleep |
114 | * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the | 114 | * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the |
115 | * HCMD the this Rx responds to. | 115 | * HCMD the this Rx responds to. |
116 | * Must be atomic and called with BH disabled. | 116 | * This callback may sleep, it is called from a threaded IRQ handler. |
117 | * @queue_full: notifies that a HW queue is full. | 117 | * @queue_full: notifies that a HW queue is full. |
118 | * Must be atomic and called with BH disabled. | 118 | * Must be atomic and called with BH disabled. |
119 | * @queue_not_full: notifies that a HW queue is not full any more. | 119 | * @queue_not_full: notifies that a HW queue is not full any more. |
120 | * Must be atomic and called with BH disabled. | 120 | * Must be atomic and called with BH disabled. |
121 | * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that | 121 | * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that |
122 | * the radio is killed. Must be atomic. | 122 | * the radio is killed. May sleep. |
123 | * @free_skb: allows the transport layer to free skbs that haven't been | 123 | * @free_skb: allows the transport layer to free skbs that haven't been |
124 | * reclaimed by the op_mode. This can happen when the driver is freed and | 124 | * reclaimed by the op_mode. This can happen when the driver is freed and |
125 | * there are Tx packets pending in the transport layer. | 125 | * there are Tx packets pending in the transport layer. |
@@ -130,8 +130,7 @@ struct iwl_cfg; | |||
130 | * called with BH disabled. | 130 | * called with BH disabled. |
131 | * @nic_config: configure NIC, called before firmware is started. | 131 | * @nic_config: configure NIC, called before firmware is started. |
132 | * May sleep | 132 | * May sleep |
133 | * @wimax_active: invoked when WiMax becomes active. Must be atomic and called | 133 | * @wimax_active: invoked when WiMax becomes active. May sleep |
134 | * with BH disabled. | ||
135 | */ | 134 | */ |
136 | struct iwl_op_mode_ops { | 135 | struct iwl_op_mode_ops { |
137 | struct iwl_op_mode *(*start)(struct iwl_trans *trans, | 136 | struct iwl_op_mode *(*start)(struct iwl_trans *trans, |
@@ -178,6 +177,7 @@ static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, | |||
178 | struct iwl_rx_cmd_buffer *rxb, | 177 | struct iwl_rx_cmd_buffer *rxb, |
179 | struct iwl_device_cmd *cmd) | 178 | struct iwl_device_cmd *cmd) |
180 | { | 179 | { |
180 | might_sleep(); | ||
181 | return op_mode->ops->rx(op_mode, rxb, cmd); | 181 | return op_mode->ops->rx(op_mode, rxb, cmd); |
182 | } | 182 | } |
183 | 183 | ||
@@ -196,6 +196,7 @@ static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode, | |||
196 | static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, | 196 | static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, |
197 | bool state) | 197 | bool state) |
198 | { | 198 | { |
199 | might_sleep(); | ||
199 | op_mode->ops->hw_rf_kill(op_mode, state); | 200 | op_mode->ops->hw_rf_kill(op_mode, state); |
200 | } | 201 | } |
201 | 202 | ||
@@ -223,6 +224,7 @@ static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode) | |||
223 | 224 | ||
224 | static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) | 225 | static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) |
225 | { | 226 | { |
227 | might_sleep(); | ||
226 | op_mode->ops->wimax_active(op_mode); | 228 | op_mode->ops->wimax_active(op_mode); |
227 | } | 229 | } |
228 | 230 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 0a3d4df5f434..8c7bec6b9a0b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -65,6 +65,7 @@ | |||
65 | 65 | ||
66 | #include <linux/ieee80211.h> | 66 | #include <linux/ieee80211.h> |
67 | #include <linux/mm.h> /* for page_address */ | 67 | #include <linux/mm.h> /* for page_address */ |
68 | #include <linux/lockdep.h> | ||
68 | 69 | ||
69 | #include "iwl-debug.h" | 70 | #include "iwl-debug.h" |
70 | #include "iwl-config.h" | 71 | #include "iwl-config.h" |
@@ -526,6 +527,10 @@ struct iwl_trans { | |||
526 | 527 | ||
527 | struct dentry *dbgfs_dir; | 528 | struct dentry *dbgfs_dir; |
528 | 529 | ||
530 | #ifdef CONFIG_LOCKDEP | ||
531 | struct lockdep_map sync_cmd_lockdep_map; | ||
532 | #endif | ||
533 | |||
529 | /* pointer to trans specific struct */ | 534 | /* pointer to trans specific struct */ |
530 | /*Ensure that this pointer will always be aligned to sizeof pointer */ | 535 | /*Ensure that this pointer will always be aligned to sizeof pointer */ |
531 | char trans_specific[0] __aligned(sizeof(void *)); | 536 | char trans_specific[0] __aligned(sizeof(void *)); |
@@ -602,12 +607,22 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans, | |||
602 | } | 607 | } |
603 | 608 | ||
604 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, | 609 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, |
605 | struct iwl_host_cmd *cmd) | 610 | struct iwl_host_cmd *cmd) |
606 | { | 611 | { |
612 | int ret; | ||
613 | |||
607 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | 614 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, |
608 | "%s bad state = %d", __func__, trans->state); | 615 | "%s bad state = %d", __func__, trans->state); |
609 | 616 | ||
610 | return trans->ops->send_cmd(trans, cmd); | 617 | if (!(cmd->flags & CMD_ASYNC)) |
618 | lock_map_acquire_read(&trans->sync_cmd_lockdep_map); | ||
619 | |||
620 | ret = trans->ops->send_cmd(trans, cmd); | ||
621 | |||
622 | if (!(cmd->flags & CMD_ASYNC)) | ||
623 | lock_map_release(&trans->sync_cmd_lockdep_map); | ||
624 | |||
625 | return ret; | ||
611 | } | 626 | } |
612 | 627 | ||
613 | static inline struct iwl_device_cmd * | 628 | static inline struct iwl_device_cmd * |
@@ -791,4 +806,14 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags) | |||
791 | int __must_check iwl_pci_register_driver(void); | 806 | int __must_check iwl_pci_register_driver(void); |
792 | void iwl_pci_unregister_driver(void); | 807 | void iwl_pci_unregister_driver(void); |
793 | 808 | ||
809 | static inline void trans_lockdep_init(struct iwl_trans *trans) | ||
810 | { | ||
811 | #ifdef CONFIG_LOCKDEP | ||
812 | static struct lock_class_key __key; | ||
813 | |||
814 | lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map", | ||
815 | &__key, 0); | ||
816 | #endif | ||
817 | } | ||
818 | |||
794 | #endif /* __iwl_trans_h__ */ | 819 | #endif /* __iwl_trans_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 52da375e5740..3f3ce91ad5c2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -121,7 +121,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | |||
121 | 121 | ||
122 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | 122 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); |
123 | 123 | ||
124 | ieee80211_rx(mvm->hw, skb); | 124 | ieee80211_rx_ni(mvm->hw, skb); |
125 | } | 125 | } |
126 | 126 | ||
127 | /* | 127 | /* |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index cada8efe0cca..6b67ce3f679c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -620,7 +620,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
620 | seq_ctl = le16_to_cpu(hdr->seq_ctrl); | 620 | seq_ctl = le16_to_cpu(hdr->seq_ctrl); |
621 | } | 621 | } |
622 | 622 | ||
623 | ieee80211_tx_status(mvm->hw, skb); | 623 | ieee80211_tx_status_ni(mvm->hw, skb); |
624 | } | 624 | } |
625 | 625 | ||
626 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE) { | 626 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE) { |
@@ -663,12 +663,12 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
663 | struct iwl_mvm_tid_data *tid_data = | 663 | struct iwl_mvm_tid_data *tid_data = |
664 | &mvmsta->tid_data[tid]; | 664 | &mvmsta->tid_data[tid]; |
665 | 665 | ||
666 | spin_lock(&mvmsta->lock); | 666 | spin_lock_bh(&mvmsta->lock); |
667 | tid_data->next_reclaimed = next_reclaimed; | 667 | tid_data->next_reclaimed = next_reclaimed; |
668 | IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", | 668 | IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", |
669 | next_reclaimed); | 669 | next_reclaimed); |
670 | iwl_mvm_check_ratid_empty(mvm, sta, tid); | 670 | iwl_mvm_check_ratid_empty(mvm, sta, tid); |
671 | spin_unlock(&mvmsta->lock); | 671 | spin_unlock_bh(&mvmsta->lock); |
672 | } | 672 | } |
673 | 673 | ||
674 | #ifdef CONFIG_PM_SLEEP | 674 | #ifdef CONFIG_PM_SLEEP |
@@ -832,7 +832,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
832 | return 0; | 832 | return 0; |
833 | } | 833 | } |
834 | 834 | ||
835 | spin_lock(&mvmsta->lock); | 835 | spin_lock_bh(&mvmsta->lock); |
836 | 836 | ||
837 | __skb_queue_head_init(&reclaimed_skbs); | 837 | __skb_queue_head_init(&reclaimed_skbs); |
838 | 838 | ||
@@ -886,13 +886,13 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
886 | } | 886 | } |
887 | } | 887 | } |
888 | 888 | ||
889 | spin_unlock(&mvmsta->lock); | 889 | spin_unlock_bh(&mvmsta->lock); |
890 | 890 | ||
891 | rcu_read_unlock(); | 891 | rcu_read_unlock(); |
892 | 892 | ||
893 | while (!skb_queue_empty(&reclaimed_skbs)) { | 893 | while (!skb_queue_empty(&reclaimed_skbs)) { |
894 | skb = __skb_dequeue(&reclaimed_skbs); | 894 | skb = __skb_dequeue(&reclaimed_skbs); |
895 | ieee80211_tx_status(mvm->hw, skb); | 895 | ieee80211_tx_status_ni(mvm->hw, skb); |
896 | } | 896 | } |
897 | 897 | ||
898 | return 0; | 898 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 5f6bb4e09d42..aa2a39a637dd 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -249,7 +249,6 @@ struct iwl_trans_pcie { | |||
249 | int ict_index; | 249 | int ict_index; |
250 | u32 inta; | 250 | u32 inta; |
251 | bool use_ict; | 251 | bool use_ict; |
252 | struct tasklet_struct irq_tasklet; | ||
253 | struct isr_statistics isr_stats; | 252 | struct isr_statistics isr_stats; |
254 | 253 | ||
255 | spinlock_t irq_lock; | 254 | spinlock_t irq_lock; |
@@ -330,7 +329,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); | |||
330 | * RX | 329 | * RX |
331 | ******************************************************/ | 330 | ******************************************************/ |
332 | int iwl_pcie_rx_init(struct iwl_trans *trans); | 331 | int iwl_pcie_rx_init(struct iwl_trans *trans); |
333 | void iwl_pcie_tasklet(struct iwl_trans *trans); | 332 | irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id); |
334 | int iwl_pcie_rx_stop(struct iwl_trans *trans); | 333 | int iwl_pcie_rx_stop(struct iwl_trans *trans); |
335 | void iwl_pcie_rx_free(struct iwl_trans *trans); | 334 | void iwl_pcie_rx_free(struct iwl_trans *trans); |
336 | 335 | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index a9ca1d35fa93..b0ae06d2456f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -81,10 +81,10 @@ | |||
81 | * 'processed' and 'read' driver indexes as well) | 81 | * 'processed' and 'read' driver indexes as well) |
82 | * + A received packet is processed and handed to the kernel network stack, | 82 | * + A received packet is processed and handed to the kernel network stack, |
83 | * detached from the iwl->rxq. The driver 'processed' index is updated. | 83 | * detached from the iwl->rxq. The driver 'processed' index is updated. |
84 | * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free | 84 | * + The Host/Firmware iwl->rxq is replenished at irq thread time from the |
85 | * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ | 85 | * rx_free list. If there are no allocated buffers in iwl->rxq->rx_free, |
86 | * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there | 86 | * the READ INDEX is not incremented and iwl->status(RX_STALLED) is set. |
87 | * were enough free buffers and RX_STALLED is set it is cleared. | 87 | * If there were enough free buffers and RX_STALLED is set it is cleared. |
88 | * | 88 | * |
89 | * | 89 | * |
90 | * Driver sequence: | 90 | * Driver sequence: |
@@ -214,9 +214,9 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) | |||
214 | /* | 214 | /* |
215 | * If the device isn't enabled - not need to try to add buffers... | 215 | * If the device isn't enabled - not need to try to add buffers... |
216 | * This can happen when we stop the device and still have an interrupt | 216 | * This can happen when we stop the device and still have an interrupt |
217 | * pending. We stop the APM before we sync the interrupts / tasklets | 217 | * pending. We stop the APM before we sync the interrupts because we |
218 | * because we have to (see comment there). On the other hand, since | 218 | * have to (see comment there). On the other hand, since the APM is |
219 | * the APM is stopped, we cannot access the HW (in particular not prph). | 219 | * stopped, we cannot access the HW (in particular not prph). |
220 | * So don't try to restock if the APM has been already stopped. | 220 | * So don't try to restock if the APM has been already stopped. |
221 | */ | 221 | */ |
222 | if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) | 222 | if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) |
@@ -796,11 +796,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) | |||
796 | clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); | 796 | clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); |
797 | wake_up(&trans_pcie->wait_command_queue); | 797 | wake_up(&trans_pcie->wait_command_queue); |
798 | 798 | ||
799 | local_bh_disable(); | ||
799 | iwl_op_mode_nic_error(trans->op_mode); | 800 | iwl_op_mode_nic_error(trans->op_mode); |
801 | local_bh_enable(); | ||
800 | } | 802 | } |
801 | 803 | ||
802 | void iwl_pcie_tasklet(struct iwl_trans *trans) | 804 | irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) |
803 | { | 805 | { |
806 | struct iwl_trans *trans = dev_id; | ||
804 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 807 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
805 | struct isr_statistics *isr_stats = &trans_pcie->isr_stats; | 808 | struct isr_statistics *isr_stats = &trans_pcie->isr_stats; |
806 | u32 inta = 0; | 809 | u32 inta = 0; |
@@ -811,6 +814,8 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | |||
811 | u32 inta_mask; | 814 | u32 inta_mask; |
812 | #endif | 815 | #endif |
813 | 816 | ||
817 | lock_map_acquire(&trans->sync_cmd_lockdep_map); | ||
818 | |||
814 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); | 819 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); |
815 | 820 | ||
816 | /* Ack/clear/reset pending uCode interrupts. | 821 | /* Ack/clear/reset pending uCode interrupts. |
@@ -855,7 +860,7 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | |||
855 | 860 | ||
856 | handled |= CSR_INT_BIT_HW_ERR; | 861 | handled |= CSR_INT_BIT_HW_ERR; |
857 | 862 | ||
858 | return; | 863 | goto out; |
859 | } | 864 | } |
860 | 865 | ||
861 | #ifdef CONFIG_IWLWIFI_DEBUG | 866 | #ifdef CONFIG_IWLWIFI_DEBUG |
@@ -1005,6 +1010,10 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | |||
1005 | /* Re-enable RF_KILL if it occurred */ | 1010 | /* Re-enable RF_KILL if it occurred */ |
1006 | else if (handled & CSR_INT_BIT_RF_KILL) | 1011 | else if (handled & CSR_INT_BIT_RF_KILL) |
1007 | iwl_enable_rfkill_int(trans); | 1012 | iwl_enable_rfkill_int(trans); |
1013 | |||
1014 | out: | ||
1015 | lock_map_release(&trans->sync_cmd_lockdep_map); | ||
1016 | return IRQ_HANDLED; | ||
1008 | } | 1017 | } |
1009 | 1018 | ||
1010 | /****************************************************************************** | 1019 | /****************************************************************************** |
@@ -1127,7 +1136,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | |||
1127 | 1136 | ||
1128 | /* Disable (but don't clear!) interrupts here to avoid | 1137 | /* Disable (but don't clear!) interrupts here to avoid |
1129 | * back-to-back ISRs and sporadic interrupts from our NIC. | 1138 | * back-to-back ISRs and sporadic interrupts from our NIC. |
1130 | * If we have something to service, the tasklet will re-enable ints. | 1139 | * If we have something to service, the irq thread will re-enable ints. |
1131 | * If we *don't* have something, we'll re-enable before leaving here. */ | 1140 | * If we *don't* have something, we'll re-enable before leaving here. */ |
1132 | inta_mask = iwl_read32(trans, CSR_INT_MASK); | 1141 | inta_mask = iwl_read32(trans, CSR_INT_MASK); |
1133 | iwl_write32(trans, CSR_INT_MASK, 0x00000000); | 1142 | iwl_write32(trans, CSR_INT_MASK, 0x00000000); |
@@ -1167,9 +1176,9 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | |||
1167 | #endif | 1176 | #endif |
1168 | 1177 | ||
1169 | trans_pcie->inta |= inta; | 1178 | trans_pcie->inta |= inta; |
1170 | /* iwl_pcie_tasklet() will service interrupts and re-enable them */ | 1179 | /* the thread will service interrupts and re-enable them */ |
1171 | if (likely(inta)) | 1180 | if (likely(inta)) |
1172 | tasklet_schedule(&trans_pcie->irq_tasklet); | 1181 | return IRQ_WAKE_THREAD; |
1173 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | 1182 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && |
1174 | !trans_pcie->inta) | 1183 | !trans_pcie->inta) |
1175 | iwl_enable_interrupts(trans); | 1184 | iwl_enable_interrupts(trans); |
@@ -1277,9 +1286,10 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data) | |||
1277 | trans_pcie->inta |= inta; | 1286 | trans_pcie->inta |= inta; |
1278 | 1287 | ||
1279 | /* iwl_pcie_tasklet() will service interrupts and re-enable them */ | 1288 | /* iwl_pcie_tasklet() will service interrupts and re-enable them */ |
1280 | if (likely(inta)) | 1289 | if (likely(inta)) { |
1281 | tasklet_schedule(&trans_pcie->irq_tasklet); | 1290 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); |
1282 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | 1291 | return IRQ_WAKE_THREAD; |
1292 | } else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | ||
1283 | !trans_pcie->inta) { | 1293 | !trans_pcie->inta) { |
1284 | /* Allow interrupt if was disabled by this handler and | 1294 | /* Allow interrupt if was disabled by this handler and |
1285 | * no tasklet was schedules, We should not enable interrupt, | 1295 | * no tasklet was schedules, We should not enable interrupt, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 56d4f72500bc..17bedc50e753 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -760,7 +760,6 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) | |||
760 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 760 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
761 | 761 | ||
762 | synchronize_irq(trans_pcie->pci_dev->irq); | 762 | synchronize_irq(trans_pcie->pci_dev->irq); |
763 | tasklet_kill(&trans_pcie->irq_tasklet); | ||
764 | 763 | ||
765 | iwl_pcie_tx_free(trans); | 764 | iwl_pcie_tx_free(trans); |
766 | iwl_pcie_rx_free(trans); | 765 | iwl_pcie_rx_free(trans); |
@@ -1480,6 +1479,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
1480 | 1479 | ||
1481 | trans->ops = &trans_ops_pcie; | 1480 | trans->ops = &trans_ops_pcie; |
1482 | trans->cfg = cfg; | 1481 | trans->cfg = cfg; |
1482 | trans_lockdep_init(trans); | ||
1483 | trans_pcie->trans = trans; | 1483 | trans_pcie->trans = trans; |
1484 | spin_lock_init(&trans_pcie->irq_lock); | 1484 | spin_lock_init(&trans_pcie->irq_lock); |
1485 | spin_lock_init(&trans_pcie->reg_lock); | 1485 | spin_lock_init(&trans_pcie->reg_lock); |
@@ -1567,15 +1567,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
1567 | 1567 | ||
1568 | trans_pcie->inta_mask = CSR_INI_SET_MASK; | 1568 | trans_pcie->inta_mask = CSR_INI_SET_MASK; |
1569 | 1569 | ||
1570 | tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) | ||
1571 | iwl_pcie_tasklet, (unsigned long)trans); | ||
1572 | |||
1573 | if (iwl_pcie_alloc_ict(trans)) | 1570 | if (iwl_pcie_alloc_ict(trans)) |
1574 | goto out_free_cmd_pool; | 1571 | goto out_free_cmd_pool; |
1575 | 1572 | ||
1576 | err = request_irq(pdev->irq, iwl_pcie_isr_ict, | 1573 | if (request_threaded_irq(pdev->irq, iwl_pcie_isr_ict, |
1577 | IRQF_SHARED, DRV_NAME, trans); | 1574 | iwl_pcie_irq_handler, |
1578 | if (err) { | 1575 | IRQF_SHARED, DRV_NAME, trans)) { |
1579 | IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); | 1576 | IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); |
1580 | goto out_free_ict; | 1577 | goto out_free_ict; |
1581 | } | 1578 | } |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 041127ad372a..8e9e3212fe78 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -926,7 +926,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | |||
926 | if (WARN_ON(txq_id == trans_pcie->cmd_queue)) | 926 | if (WARN_ON(txq_id == trans_pcie->cmd_queue)) |
927 | return; | 927 | return; |
928 | 928 | ||
929 | spin_lock(&txq->lock); | 929 | spin_lock_bh(&txq->lock); |
930 | 930 | ||
931 | if (txq->q.read_ptr == tfd_num) | 931 | if (txq->q.read_ptr == tfd_num) |
932 | goto out; | 932 | goto out; |
@@ -970,7 +970,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | |||
970 | if (iwl_queue_space(&txq->q) > txq->q.low_mark) | 970 | if (iwl_queue_space(&txq->q) > txq->q.low_mark) |
971 | iwl_wake_queue(trans, txq); | 971 | iwl_wake_queue(trans, txq); |
972 | out: | 972 | out: |
973 | spin_unlock(&txq->lock); | 973 | spin_unlock_bh(&txq->lock); |
974 | } | 974 | } |
975 | 975 | ||
976 | /* | 976 | /* |
@@ -1371,7 +1371,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, | |||
1371 | return; | 1371 | return; |
1372 | } | 1372 | } |
1373 | 1373 | ||
1374 | spin_lock(&txq->lock); | 1374 | spin_lock_bh(&txq->lock); |
1375 | 1375 | ||
1376 | cmd_index = get_cmd_index(&txq->q, index); | 1376 | cmd_index = get_cmd_index(&txq->q, index); |
1377 | cmd = txq->entries[cmd_index].cmd; | 1377 | cmd = txq->entries[cmd_index].cmd; |
@@ -1405,7 +1405,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, | |||
1405 | 1405 | ||
1406 | meta->flags = 0; | 1406 | meta->flags = 0; |
1407 | 1407 | ||
1408 | spin_unlock(&txq->lock); | 1408 | spin_unlock_bh(&txq->lock); |
1409 | } | 1409 | } |
1410 | 1410 | ||
1411 | #define HOST_COMPLETE_TIMEOUT (2 * HZ) | 1411 | #define HOST_COMPLETE_TIMEOUT (2 * HZ) |