Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next
authorJohannes Berg <johannes.berg@intel.com>
Tue, 12 Feb 2013 15:52:04 +0000 (16:52 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 12 Feb 2013 15:52:11 +0000 (16:52 +0100)
19 files changed:
drivers/net/wireless/iwlwifi/dvm/rx.c
drivers/net/wireless/iwlwifi/dvm/sta.c
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/iwl-op-mode.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/quota.c
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c

index e8d5b90abf5ccfb56c4c59fff0324e3a456b5cf7..a4eed2055fdbe590f1d8325fffcd84d171aff19d 100644 (file)
@@ -790,7 +790,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
 
        memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
-       ieee80211_rx(priv->hw, skb);
+       ieee80211_rx_ni(priv->hw, skb);
 }
 
 static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
index ab768045696b48598ba91f889a22c87403f73c21..2d33760a9dc229225cc76676822fcf55c4f7dd70 100644 (file)
@@ -77,7 +77,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv,
        IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
                       sta_id);
 
-       spin_lock(&priv->sta_lock);
+       spin_lock_bh(&priv->sta_lock);
 
        switch (add_sta_resp->status) {
        case ADD_STA_SUCCESS_MSK:
@@ -119,7 +119,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv,
                       priv->stations[sta_id].sta.mode ==
                       STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
                       addsta->sta.addr);
-       spin_unlock(&priv->sta_lock);
+       spin_unlock_bh(&priv->sta_lock);
 
        return ret;
 }
index 7b0550d35a91e25d009d310f3cadf01e35f1df70..4ece5ea81b8606b88a6fb124e8dfbd7bb95ea09c 100644 (file)
@@ -1117,7 +1117,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
        sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
                IWLAGN_TX_RES_RA_POS;
 
-       spin_lock(&priv->sta_lock);
+       spin_lock_bh(&priv->sta_lock);
 
        if (is_agg)
                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,
                           le16_to_cpu(tx_resp->seq_ctl));
 
        iwl_check_abort_status(priv, tx_resp->frame_count, status);
-       spin_unlock(&priv->sta_lock);
+       spin_unlock_bh(&priv->sta_lock);
 
        while (!skb_queue_empty(&skbs)) {
                skb = __skb_dequeue(&skbs);
-               ieee80211_tx_status(priv->hw, skb);
+               ieee80211_tx_status_ni(priv->hw, skb);
        }
 
        if (is_offchannel_skb)
@@ -1290,12 +1290,12 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
        tid = ba_resp->tid;
        agg = &priv->tid_data[sta_id][tid].agg;
 
-       spin_lock(&priv->sta_lock);
+       spin_lock_bh(&priv->sta_lock);
 
        if (unlikely(!agg->wait_for_ba)) {
                if (unlikely(ba_resp->bitmap))
                        IWL_ERR(priv, "Received BA when not expected\n");
-               spin_unlock(&priv->sta_lock);
+               spin_unlock_bh(&priv->sta_lock);
                return 0;
        }
 
@@ -1309,7 +1309,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
                IWL_DEBUG_TX_QUEUES(priv,
                                    "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n",
                                    scd_flow, sta_id, tid, agg->txq_id);
-               spin_unlock(&priv->sta_lock);
+               spin_unlock_bh(&priv->sta_lock);
                return 0;
        }
 
@@ -1378,11 +1378,11 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
                }
        }
 
-       spin_unlock(&priv->sta_lock);
+       spin_unlock_bh(&priv->sta_lock);
 
        while (!skb_queue_empty(&reclaimed_skbs)) {
                skb = __skb_dequeue(&reclaimed_skbs);
-               ieee80211_tx_status(priv->hw, skb);
+               ieee80211_tx_status_ni(priv->hw, skb);
        }
 
        return 0;
index dc792584f401f5429d27f4dcbc84048ebea15d1e..4a680019e1174a122ee2d5062d8bab909306a95f 100644 (file)
@@ -113,13 +113,13 @@ struct iwl_cfg;
  *     May sleep
  * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the
  *     HCMD the this Rx responds to.
- *     Must be atomic and called with BH disabled.
+ *     This callback may sleep, it is called from a threaded IRQ handler.
  * @queue_full: notifies that a HW queue is full.
  *     Must be atomic and called with BH disabled.
  * @queue_not_full: notifies that a HW queue is not full any more.
  *     Must be atomic and called with BH disabled.
  * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that
- *     the radio is killed. Must be atomic.
+ *     the radio is killed. May sleep.
  * @free_skb: allows the transport layer to free skbs that haven't been
  *     reclaimed by the op_mode. This can happen when the driver is freed and
  *     there are Tx packets pending in the transport layer.
@@ -130,8 +130,7 @@ struct iwl_cfg;
  *     called with BH disabled.
  * @nic_config: configure NIC, called before firmware is started.
  *     May sleep
- * @wimax_active: invoked when WiMax becomes active.  Must be atomic and called
- *     with BH disabled.
+ * @wimax_active: invoked when WiMax becomes active. May sleep
  */
 struct iwl_op_mode_ops {
        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,
                                  struct iwl_rx_cmd_buffer *rxb,
                                  struct iwl_device_cmd *cmd)
 {
+       might_sleep();
        return op_mode->ops->rx(op_mode, rxb, cmd);
 }
 
@@ -196,6 +196,7 @@ static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode,
 static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode,
                                          bool state)
 {
+       might_sleep();
        op_mode->ops->hw_rf_kill(op_mode, state);
 }
 
@@ -223,6 +224,7 @@ static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode)
 
 static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode)
 {
+       might_sleep();
        op_mode->ops->wimax_active(op_mode);
 }
 
index 0a3d4df5f434f7e698e9ff2790119f315fb1609a..8c7bec6b9a0be92d29136a47fc20f920a5ce7a6d 100644 (file)
@@ -65,6 +65,7 @@
 
 #include <linux/ieee80211.h>
 #include <linux/mm.h> /* for page_address */
+#include <linux/lockdep.h>
 
 #include "iwl-debug.h"
 #include "iwl-config.h"
@@ -526,6 +527,10 @@ struct iwl_trans {
 
        struct dentry *dbgfs_dir;
 
+#ifdef CONFIG_LOCKDEP
+       struct lockdep_map sync_cmd_lockdep_map;
+#endif
+
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
        char trans_specific[0] __aligned(sizeof(void *));
@@ -602,12 +607,22 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
 }
 
 static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
-                               struct iwl_host_cmd *cmd)
+                                    struct iwl_host_cmd *cmd)
 {
+       int ret;
+
        WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
                  "%s bad state = %d", __func__, trans->state);
 
-       return trans->ops->send_cmd(trans, cmd);
+       if (!(cmd->flags & CMD_ASYNC))
+               lock_map_acquire_read(&trans->sync_cmd_lockdep_map);
+
+       ret = trans->ops->send_cmd(trans, cmd);
+
+       if (!(cmd->flags & CMD_ASYNC))
+               lock_map_release(&trans->sync_cmd_lockdep_map);
+
+       return ret;
 }
 
 static inline struct iwl_device_cmd *
@@ -791,4 +806,14 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
 int __must_check iwl_pci_register_driver(void);
 void iwl_pci_unregister_driver(void);
 
+static inline void trans_lockdep_init(struct iwl_trans *trans)
+{
+#ifdef CONFIG_LOCKDEP
+       static struct lock_class_key __key;
+
+       lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map",
+                        &__key, 0);
+#endif
+}
+
 #endif /* __iwl_trans_h__ */
index 9a95c374990db090b3a5dfc5310e4e5f8acbee44..5b2c675a87525a0072a0c3c64295a74272c4d2a4 100644 (file)
@@ -97,14 +97,14 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
        struct inet6_ifaddr *ifa;
        int idx = 0;
 
-       read_lock(&idev->lock);
+       read_lock_bh(&idev->lock);
        list_for_each_entry(ifa, &idev->addr_list, if_list) {
                mvmvif->target_ipv6_addrs[idx] = ifa->addr;
                idx++;
                if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS)
                        break;
        }
-       read_unlock(&idev->lock);
+       read_unlock_bh(&idev->lock);
 
        mvmvif->num_target_ipv6_addrs = idx;
 }
index 9fd49db32a32192d7e47da8d10fbd3596adabdc9..23eebda848b05ae64f9ae8dfb6ce5647dded4b19 100644 (file)
@@ -633,6 +633,9 @@ struct iwl_binding_cmd {
        __le32 phy;
 } __packed; /* BINDING_CMD_API_S_VER_1 */
 
+/* The maximal number of fragments in the FW's schedule session */
+#define IWL_MVM_MAX_QUOTA 128
+
 /**
  * struct iwl_time_quota_data - configuration of time quota per binding
  * @id_and_color: ID and color of the relevant Binding
index 90473c2ba1c7b1b629cd29370e2bd2dad0212fe1..d3d959db03a9727e7033a871fc4717654dc3ec10 100644 (file)
@@ -621,10 +621,6 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
                          (flags & CT_KILL_CARD_DISABLED) ?
                          "Reached" : "Not reached");
 
-       if (flags & CARD_DISABLED_MSK)
-               iwl_write32(mvm->trans, CSR_UCODE_DRV_GP1_SET,
-                           CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
        return 0;
 }
 
index ce6127caabdf87791dd41ca12e22d5adfe3bc3c0..e0d79e328d0c8f499969322231fb295c76cc2aef 100644 (file)
@@ -475,7 +475,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
        if (mvm->vif_count > 1) {
                IWL_DEBUG_MAC80211(mvm,
                                   "Disable power on existing interfaces\n");
-               ieee80211_iterate_active_interfaces(
+               ieee80211_iterate_active_interfaces_atomic(
                                            mvm->hw,
                                            IEEE80211_IFACE_ITER_NORMAL,
                                            iwl_mvm_pm_disable_iterator, mvm);
index 63628739cf4a9494597b63c364a34f31f6a0ad55..5a92a4978795420acbd363ca0ca94037e47f5b28 100644 (file)
@@ -194,7 +194,7 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                        cmd.id_and_color, iwlmvm_mod_params.power_scheme,
                        le16_to_cpu(cmd.flags));
 
-       return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC,
+       return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC,
                                    sizeof(cmd), &cmd);
 }
 
index 2d4611a563c5ce1d498d35947e39044e2302465b..9256284681466fe416ffc84c10c0cc74a14d342e 100644 (file)
@@ -131,7 +131,7 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
 int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
 {
        struct iwl_time_quota_cmd cmd;
-       int i, idx, ret;
+       int i, idx, ret, num_active_bindings, quota, quota_rem;
        struct iwl_mvm_quota_iterator_data data = {
                .n_interfaces = {},
                .colors = { -1, -1, -1, -1 },
@@ -156,20 +156,39 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
                iwl_mvm_quota_iterator(&data, newvif->addr, newvif);
        }
 
+       /*
+        * The FW's scheduling session consists of
+        * IWL_MVM_MAX_QUOTA fragments. Divide these fragments
+        * equally between all the bindings that require quota
+        */
+       num_active_bindings = 0;
+       for (i = 0; i < MAX_BINDINGS; i++) {
+               cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID);
+               if (data.n_interfaces[i] > 0)
+                       num_active_bindings++;
+       }
+
+       if (!num_active_bindings)
+               goto send_cmd;
+
+       quota = IWL_MVM_MAX_QUOTA / num_active_bindings;
+       quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings;
+
        for (idx = 0, i = 0; i < MAX_BINDINGS; i++) {
                if (data.n_interfaces[i] <= 0)
                        continue;
 
                cmd.quotas[idx].id_and_color =
                        cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i]));
-               cmd.quotas[idx].quota = cpu_to_le32(100);
-               cmd.quotas[idx].max_duration = cpu_to_le32(1000);
+               cmd.quotas[idx].quota = cpu_to_le32(quota);
+               cmd.quotas[idx].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA);
                idx++;
        }
 
-       for (i = idx; i < MAX_BINDINGS; i++)
-               cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID);
+       /* Give the remainder of the session to the first binding */
+       le32_add_cpu(&cmd.quotas[0].quota, quota_rem);
 
+send_cmd:
        ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC,
                                   sizeof(cmd), &cmd);
        if (ret)
index 52da375e5740cae55327aaec64074a11b460f51e..3f3ce91ad5c27671eb639dbf0941abaea6a6223b 100644 (file)
@@ -121,7 +121,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
 
        memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
-       ieee80211_rx(mvm->hw, skb);
+       ieee80211_rx_ni(mvm->hw, skb);
 }
 
 /*
index 69603c3b2b39b05ac13a268cb351dcedde27f627..6b22bacdc1df64bc1f64461036485fcd33e9a21e 100644 (file)
@@ -1116,7 +1116,8 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
        if (WARN_ON_ONCE(mvm_sta->vif != vif))
                return -EINVAL;
 
-       key_flags = cpu_to_le16(keyconf->keyidx & STA_KEY_FLG_KEYID_MSK);
+       key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
+                                STA_KEY_FLG_KEYID_MSK);
        key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP);
        key_flags |= cpu_to_le16(STA_KEY_NOT_VALID);
 
@@ -1154,14 +1155,26 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
                             struct ieee80211_sta *sta, u32 iv32,
                             u16 *phase1key)
 {
-       struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+       struct iwl_mvm_sta *mvm_sta;
        u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta);
 
-       if (sta_id == IWL_INVALID_STATION)
+       if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
                return;
 
+       rcu_read_lock();
+
+       if (!sta) {
+               sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+               if (WARN_ON(IS_ERR_OR_NULL(sta))) {
+                       rcu_read_unlock();
+                       return;
+               }
+       }
+
+       mvm_sta = (void *)sta->drv_priv;
        iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id,
                             iv32, phase1key, CMD_ASYNC);
+       rcu_read_unlock();
 }
 
 void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id)
index b9f076f4f17ca2eb0c3feaa668ebde7e4fd4de28..4d62a5d4254d00c6c4525a23ad89f11bc99910e0 100644 (file)
 #define TU_TO_JIFFIES(_tu)     (usecs_to_jiffies((_tu) * 1024))
 #define MSEC_TO_TU(_msec)      (_msec*1000/1024)
 
+/* For ROC use a TE type which has priority high enough to be scheduled when
+ * there is a concurrent BSS or GO/AP. Currently, use a TE type that has
+ * priority similar to the TE priority used for action scans by the FW.
+ * TODO: This needs to be changed, based on the reason for the ROC, i.e., use
+ * TE_P2P_DEVICE_DISCOVERABLE for remain on channel without mgmt skb, and use
+ * TE_P2P_DEVICE_ACTION_SCAN
+ */
+#define IWL_MVM_ROC_TE_TYPE TE_P2P_DEVICE_ACTION_SCAN
+
 void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
                           struct iwl_mvm_time_event_data *te_data)
 {
@@ -436,7 +445,7 @@ static bool iwl_mvm_roc_te_notif(struct iwl_notif_wait_data *notif_wait,
        u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color);
 
        /* until we do something else */
-       WARN_ON(te_data->id != TE_P2P_DEVICE_DISCOVERABLE);
+       WARN_ON(te_data->id != IWL_MVM_ROC_TE_TYPE);
 
        switch (pkt->hdr.cmd) {
        case TIME_EVENT_CMD:
@@ -483,7 +492,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
        time_cmd.id_and_color =
                cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
-       time_cmd.id = cpu_to_le32(TE_P2P_DEVICE_DISCOVERABLE);
+       time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE);
 
        time_cmd.apply_time = cpu_to_le32(0);
        time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT);
@@ -492,7 +501,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        time_cmd.interval = cpu_to_le32(1);
 
        /*
-        * TE_P2P_DEVICE_DISCOVERABLE can have lower priority than other events
+        * IWL_MVM_ROC_TE_TYPE can have lower priority than other events
         * that are being scheduled by the driver/fw, and thus it might not be
         * scheduled. To improve the chances of it being scheduled, allow it to
         * be fragmented.
index cada8efe0ccac3d4f80f1542feff64442eb486ea..6b67ce3f679ceb8ad4907c14c32926d0828f9f75 100644 (file)
@@ -620,7 +620,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                        seq_ctl = le16_to_cpu(hdr->seq_ctrl);
                }
 
-               ieee80211_tx_status(mvm->hw, skb);
+               ieee80211_tx_status_ni(mvm->hw, skb);
        }
 
        if (txq_id >= IWL_FIRST_AMPDU_QUEUE) {
@@ -663,12 +663,12 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                        struct iwl_mvm_tid_data *tid_data =
                                &mvmsta->tid_data[tid];
 
-                       spin_lock(&mvmsta->lock);
+                       spin_lock_bh(&mvmsta->lock);
                        tid_data->next_reclaimed = next_reclaimed;
                        IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n",
                                           next_reclaimed);
                        iwl_mvm_check_ratid_empty(mvm, sta, tid);
-                       spin_unlock(&mvmsta->lock);
+                       spin_unlock_bh(&mvmsta->lock);
                }
 
 #ifdef CONFIG_PM_SLEEP
@@ -832,7 +832,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                return 0;
        }
 
-       spin_lock(&mvmsta->lock);
+       spin_lock_bh(&mvmsta->lock);
 
        __skb_queue_head_init(&reclaimed_skbs);
 
@@ -886,13 +886,13 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                }
        }
 
-       spin_unlock(&mvmsta->lock);
+       spin_unlock_bh(&mvmsta->lock);
 
        rcu_read_unlock();
 
        while (!skb_queue_empty(&reclaimed_skbs)) {
                skb = __skb_dequeue(&reclaimed_skbs);
-               ieee80211_tx_status(mvm->hw, skb);
+               ieee80211_tx_status_ni(mvm->hw, skb);
        }
 
        return 0;
index 5f6bb4e09d422bf6c51dcb29b44a091f5d9eed66..aa2a39a637ddebb15e2b1f390eaa84c839af3dda 100644 (file)
@@ -249,7 +249,6 @@ struct iwl_trans_pcie {
        int ict_index;
        u32 inta;
        bool use_ict;
-       struct tasklet_struct irq_tasklet;
        struct isr_statistics isr_stats;
 
        spinlock_t irq_lock;
@@ -330,7 +329,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans);
 * RX
 ******************************************************/
 int iwl_pcie_rx_init(struct iwl_trans *trans);
-void iwl_pcie_tasklet(struct iwl_trans *trans);
+irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id);
 int iwl_pcie_rx_stop(struct iwl_trans *trans);
 void iwl_pcie_rx_free(struct iwl_trans *trans);
 
index a9ca1d35fa9382831c2eae6e8587954b0cc5872d..b0ae06d2456f1c388ba47fcdbb88f74063ea1162 100644 (file)
  *   'processed' and 'read' driver indexes as well)
  * + A received packet is processed and handed to the kernel network stack,
  *   detached from the iwl->rxq.  The driver 'processed' index is updated.
- * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
- *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
- *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
- *   were enough free buffers and RX_STALLED is set it is cleared.
+ * + The Host/Firmware iwl->rxq is replenished at irq thread time from the
+ *   rx_free list. If there are no allocated buffers in iwl->rxq->rx_free,
+ *   the READ INDEX is not incremented and iwl->status(RX_STALLED) is set.
+ *   If there were enough free buffers and RX_STALLED is set it is cleared.
  *
  *
  * Driver sequence:
@@ -214,9 +214,9 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
        /*
         * If the device isn't enabled - not need to try to add buffers...
         * This can happen when we stop the device and still have an interrupt
-        * pending. We stop the APM before we sync the interrupts / tasklets
-        * because we have to (see comment there). On the other hand, since
-        * the APM is stopped, we cannot access the HW (in particular not prph).
+        * pending. We stop the APM before we sync the interrupts because we
+        * have to (see comment there). On the other hand, since the APM is
+        * stopped, we cannot access the HW (in particular not prph).
         * So don't try to restock if the APM has been already stopped.
         */
        if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status))
@@ -796,11 +796,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
        clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
        wake_up(&trans_pcie->wait_command_queue);
 
+       local_bh_disable();
        iwl_op_mode_nic_error(trans->op_mode);
+       local_bh_enable();
 }
 
-void iwl_pcie_tasklet(struct iwl_trans *trans)
+irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
 {
+       struct iwl_trans *trans = dev_id;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
        u32 inta = 0;
@@ -811,6 +814,8 @@ void iwl_pcie_tasklet(struct iwl_trans *trans)
        u32 inta_mask;
 #endif
 
+       lock_map_acquire(&trans->sync_cmd_lockdep_map);
+
        spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
        /* Ack/clear/reset pending uCode interrupts.
@@ -855,7 +860,7 @@ void iwl_pcie_tasklet(struct iwl_trans *trans)
 
                handled |= CSR_INT_BIT_HW_ERR;
 
-               return;
+               goto out;
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -1005,6 +1010,10 @@ void iwl_pcie_tasklet(struct iwl_trans *trans)
        /* Re-enable RF_KILL if it occurred */
        else if (handled & CSR_INT_BIT_RF_KILL)
                iwl_enable_rfkill_int(trans);
+
+out:
+       lock_map_release(&trans->sync_cmd_lockdep_map);
+       return IRQ_HANDLED;
 }
 
 /******************************************************************************
@@ -1127,7 +1136,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
 
        /* Disable (but don't clear!) interrupts here to avoid
         *    back-to-back ISRs and sporadic interrupts from our NIC.
-        * If we have something to service, the tasklet will re-enable ints.
+        * If we have something to service, the irq thread will re-enable ints.
         * If we *don't* have something, we'll re-enable before leaving here. */
        inta_mask = iwl_read32(trans, CSR_INT_MASK);
        iwl_write32(trans, CSR_INT_MASK, 0x00000000);
@@ -1167,9 +1176,9 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
 #endif
 
        trans_pcie->inta |= inta;
-       /* iwl_pcie_tasklet() will service interrupts and re-enable them */
+       /* the thread will service interrupts and re-enable them */
        if (likely(inta))
-               tasklet_schedule(&trans_pcie->irq_tasklet);
+               return IRQ_WAKE_THREAD;
        else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
                 !trans_pcie->inta)
                iwl_enable_interrupts(trans);
@@ -1277,9 +1286,10 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
        trans_pcie->inta |= inta;
 
        /* iwl_pcie_tasklet() will service interrupts and re-enable them */
-       if (likely(inta))
-               tasklet_schedule(&trans_pcie->irq_tasklet);
-       else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+       if (likely(inta)) {
+               spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+               return IRQ_WAKE_THREAD;
+       } else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
                 !trans_pcie->inta) {
                /* Allow interrupt if was disabled by this handler and
                 * no tasklet was schedules, We should not enable interrupt,
index 56d4f72500bcbcf9dd6712edf67b10951d1869d8..17bedc50e753d62613055eb3662c4095fe9f41bf 100644 (file)
@@ -760,7 +760,6 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
        synchronize_irq(trans_pcie->pci_dev->irq);
-       tasklet_kill(&trans_pcie->irq_tasklet);
 
        iwl_pcie_tx_free(trans);
        iwl_pcie_rx_free(trans);
@@ -1480,6 +1479,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
 
        trans->ops = &trans_ops_pcie;
        trans->cfg = cfg;
+       trans_lockdep_init(trans);
        trans_pcie->trans = trans;
        spin_lock_init(&trans_pcie->irq_lock);
        spin_lock_init(&trans_pcie->reg_lock);
@@ -1567,15 +1567,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
 
        trans_pcie->inta_mask = CSR_INI_SET_MASK;
 
-       tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
-                    iwl_pcie_tasklet, (unsigned long)trans);
-
        if (iwl_pcie_alloc_ict(trans))
                goto out_free_cmd_pool;
 
-       err = request_irq(pdev->irq, iwl_pcie_isr_ict,
-                         IRQF_SHARED, DRV_NAME, trans);
-       if (err) {
+       if (request_threaded_irq(pdev->irq, iwl_pcie_isr_ict,
+                                iwl_pcie_irq_handler,
+                                IRQF_SHARED, DRV_NAME, trans)) {
                IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
                goto out_free_ict;
        }
index 041127ad372a73d7dbc471f1154f87e4249ad46b..8e9e3212fe784bcc8c3aea8007111669bee2441b 100644 (file)
@@ -926,7 +926,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
        if (WARN_ON(txq_id == trans_pcie->cmd_queue))
                return;
 
-       spin_lock(&txq->lock);
+       spin_lock_bh(&txq->lock);
 
        if (txq->q.read_ptr == tfd_num)
                goto out;
@@ -970,7 +970,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
        if (iwl_queue_space(&txq->q) > txq->q.low_mark)
                iwl_wake_queue(trans, txq);
 out:
-       spin_unlock(&txq->lock);
+       spin_unlock_bh(&txq->lock);
 }
 
 /*
@@ -1371,7 +1371,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
                return;
        }
 
-       spin_lock(&txq->lock);
+       spin_lock_bh(&txq->lock);
 
        cmd_index = get_cmd_index(&txq->q, index);
        cmd = txq->entries[cmd_index].cmd;
@@ -1405,7 +1405,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
 
        meta->flags = 0;
 
-       spin_unlock(&txq->lock);
+       spin_unlock_bh(&txq->lock);
 }
 
 #define HOST_COMPLETE_TIMEOUT (2 * HZ)