aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2013-05-17 14:22:17 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-05-17 14:22:17 -0400
commitd91547c00c920ed1584756d10b19c4449623efd7 (patch)
tree088fdd0fba198ba290e4eec781581d99f136541a /drivers/net/wireless
parente248ad30204eff6559b4d2d94d49d9d46c08185a (diff)
parente3d4bc8cc0230e8dc8033484666f03f87392a8c4 (diff)
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-fixes
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h27
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c12
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c17
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c6
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c13
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c48
9 files changed, 105 insertions, 22 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 191dcae8ba47..c6384555aab4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -173,6 +173,8 @@ enum {
173 REPLY_DEBUG_CMD = 0xf0, 173 REPLY_DEBUG_CMD = 0xf0,
174 DEBUG_LOG_MSG = 0xf7, 174 DEBUG_LOG_MSG = 0xf7,
175 175
176 MCAST_FILTER_CMD = 0xd0,
177
176 /* D3 commands/notifications */ 178 /* D3 commands/notifications */
177 D3_CONFIG_CMD = 0xd3, 179 D3_CONFIG_CMD = 0xd3,
178 PROT_OFFLOAD_CONFIG_CMD = 0xd4, 180 PROT_OFFLOAD_CONFIG_CMD = 0xd4,
@@ -948,4 +950,29 @@ struct iwl_set_calib_default_cmd {
948 u8 data[0]; 950 u8 data[0];
949} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */ 951} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */
950 952
953#define MAX_PORT_ID_NUM 2
954
955/**
956 * struct iwl_mcast_filter_cmd - configure multicast filter.
957 * @filter_own: Set 1 to filter out multicast packets sent by station itself
958 * @port_id: Multicast MAC addresses array specifier. This is a strange way
959 * to identify network interface adopted in host-device IF.
960 * It is used by FW as index in array of addresses. This array has
961 * MAX_PORT_ID_NUM members.
962 * @count: Number of MAC addresses in the array
963 * @pass_all: Set 1 to pass all multicast packets.
964 * @bssid: current association BSSID.
965 * @addr_list: Place holder for array of MAC addresses.
966 * IMPORTANT: add padding if necessary to ensure DWORD alignment.
967 */
968struct iwl_mcast_filter_cmd {
969 u8 filter_own;
970 u8 port_id;
971 u8 count;
972 u8 pass_all;
973 u8 bssid[6];
974 u8 reserved[2];
975 u8 addr_list[0];
976} __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */
977
951#endif /* __fw_api_h__ */ 978#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index e6eca4d66f6c..b2cc3d98e0f7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -586,10 +586,12 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
586 */ 586 */
587static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm, 587static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm,
588 struct ieee80211_vif *vif, 588 struct ieee80211_vif *vif,
589 struct iwl_mac_data_sta *ctxt_sta) 589 struct iwl_mac_data_sta *ctxt_sta,
590 bool force_assoc_off)
590{ 591{
591 /* We need the dtim_period to set the MAC as associated */ 592 /* We need the dtim_period to set the MAC as associated */
592 if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) { 593 if (vif->bss_conf.assoc && vif->bss_conf.dtim_period &&
594 !force_assoc_off) {
593 u32 dtim_offs; 595 u32 dtim_offs;
594 596
595 /* 597 /*
@@ -659,7 +661,8 @@ static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm,
659 cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON); 661 cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON);
660 662
661 /* Fill the data specific for station mode */ 663 /* Fill the data specific for station mode */
662 iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta); 664 iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta,
665 action == FW_CTXT_ACTION_ADD);
663 666
664 return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); 667 return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
665} 668}
@@ -677,7 +680,8 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm,
677 iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 680 iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
678 681
679 /* Fill the data specific for station mode */ 682 /* Fill the data specific for station mode */
680 iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta); 683 iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta,
684 action == FW_CTXT_ACTION_ADD);
681 685
682 cmd.p2p_sta.ctwin = cpu_to_le32(noa->oppps_ctwindow & 686 cmd.p2p_sta.ctwin = cpu_to_le32(noa->oppps_ctwindow &
683 IEEE80211_P2P_OPPPS_CTWINDOW_MASK); 687 IEEE80211_P2P_OPPPS_CTWINDOW_MASK);
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index dd158ec571fb..a5eb8c82f16a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -701,6 +701,20 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
701 *total_flags = 0; 701 *total_flags = 0;
702} 702}
703 703
704static int iwl_mvm_configure_mcast_filter(struct iwl_mvm *mvm,
705 struct ieee80211_vif *vif)
706{
707 struct iwl_mcast_filter_cmd mcast_filter_cmd = {
708 .pass_all = 1,
709 };
710
711 memcpy(mcast_filter_cmd.bssid, vif->bss_conf.bssid, ETH_ALEN);
712
713 return iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC,
714 sizeof(mcast_filter_cmd),
715 &mcast_filter_cmd);
716}
717
704static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, 718static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
705 struct ieee80211_vif *vif, 719 struct ieee80211_vif *vif,
706 struct ieee80211_bss_conf *bss_conf, 720 struct ieee80211_bss_conf *bss_conf,
@@ -722,6 +736,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
722 return; 736 return;
723 } 737 }
724 iwl_mvm_bt_coex_vif_assoc(mvm, vif); 738 iwl_mvm_bt_coex_vif_assoc(mvm, vif);
739 iwl_mvm_configure_mcast_filter(mvm, vif);
725 } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { 740 } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
726 /* remove AP station now that the MAC is unassoc */ 741 /* remove AP station now that the MAC is unassoc */
727 ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); 742 ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
@@ -931,7 +946,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
931 946
932 switch (cmd) { 947 switch (cmd) {
933 case STA_NOTIFY_SLEEP: 948 case STA_NOTIFY_SLEEP:
934 if (atomic_read(&mvmsta->pending_frames) > 0) 949 if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
935 ieee80211_sta_block_awake(hw, sta, true); 950 ieee80211_sta_block_awake(hw, sta, true);
936 /* 951 /*
937 * The fw updates the STA to be asleep. Tx packets on the Tx 952 * The fw updates the STA to be asleep. Tx packets on the Tx
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 8269bc562951..9f46b23801bc 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -292,6 +292,7 @@ struct iwl_mvm {
292 struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT]; 292 struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT];
293 struct work_struct sta_drained_wk; 293 struct work_struct sta_drained_wk;
294 unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; 294 unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
295 atomic_t pending_frames[IWL_MVM_STATION_COUNT];
295 296
296 /* configured by mac80211 */ 297 /* configured by mac80211 */
297 u32 rts_threshold; 298 u32 rts_threshold;
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index fe031d304d1e..b29c31a41594 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -292,6 +292,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
292 CMD(BT_COEX_PROT_ENV), 292 CMD(BT_COEX_PROT_ENV),
293 CMD(BT_PROFILE_NOTIFICATION), 293 CMD(BT_PROFILE_NOTIFICATION),
294 CMD(BT_CONFIG), 294 CMD(BT_CONFIG),
295 CMD(MCAST_FILTER_CMD),
295}; 296};
296#undef CMD 297#undef CMD
297 298
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 2157b0f8ced5..2476e43799d5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -298,6 +298,12 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
298 else 298 else
299 cmd->type = cpu_to_le32(SCAN_TYPE_FORCED); 299 cmd->type = cpu_to_le32(SCAN_TYPE_FORCED);
300 300
301 /*
302 * TODO: This is a WA due to a bug in the FW AUX framework that does not
303 * properly handle time events that fail to be scheduled
304 */
305 cmd->type = cpu_to_le32(SCAN_TYPE_FORCED);
306
301 cmd->repeats = cpu_to_le32(1); 307 cmd->repeats = cpu_to_le32(1);
302 308
303 /* 309 /*
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 0fd96e4da461..5c664ed54400 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -219,7 +219,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
219 mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF; 219 mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
220 220
221 /* HW restart, don't assume the memory has been zeroed */ 221 /* HW restart, don't assume the memory has been zeroed */
222 atomic_set(&mvm_sta->pending_frames, 0); 222 atomic_set(&mvm->pending_frames[sta_id], 0);
223 mvm_sta->tid_disable_agg = 0; 223 mvm_sta->tid_disable_agg = 0;
224 mvm_sta->tfd_queue_msk = 0; 224 mvm_sta->tfd_queue_msk = 0;
225 for (i = 0; i < IEEE80211_NUM_ACS; i++) 225 for (i = 0; i < IEEE80211_NUM_ACS; i++)
@@ -407,14 +407,21 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
407 } 407 }
408 408
409 /* 409 /*
410 * Make sure that the tx response code sees the station as -EBUSY and
411 * calls the drain worker.
412 */
413 spin_lock_bh(&mvm_sta->lock);
414 /*
410 * There are frames pending on the AC queues for this station. 415 * There are frames pending on the AC queues for this station.
411 * We need to wait until all the frames are drained... 416 * We need to wait until all the frames are drained...
412 */ 417 */
413 if (atomic_read(&mvm_sta->pending_frames)) { 418 if (atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) {
414 ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
415 rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], 419 rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
416 ERR_PTR(-EBUSY)); 420 ERR_PTR(-EBUSY));
421 spin_unlock_bh(&mvm_sta->lock);
422 ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
417 } else { 423 } else {
424 spin_unlock_bh(&mvm_sta->lock);
418 ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); 425 ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
419 rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); 426 rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
420 } 427 }
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h
index 12abd2d71835..a4ddce77aaae 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.h
@@ -274,7 +274,6 @@ struct iwl_mvm_tid_data {
274 * @bt_reduced_txpower: is reduced tx power enabled for this station 274 * @bt_reduced_txpower: is reduced tx power enabled for this station
275 * @lock: lock to protect the whole struct. Since %tid_data is access from Tx 275 * @lock: lock to protect the whole struct. Since %tid_data is access from Tx
276 * and from Tx response flow, it needs a spinlock. 276 * and from Tx response flow, it needs a spinlock.
277 * @pending_frames: number of frames for this STA on the shared Tx queues.
278 * @tid_data: per tid data. Look at %iwl_mvm_tid_data. 277 * @tid_data: per tid data. Look at %iwl_mvm_tid_data.
279 * 278 *
280 * When mac80211 creates a station it reserves some space (hw->sta_data_size) 279 * When mac80211 creates a station it reserves some space (hw->sta_data_size)
@@ -290,7 +289,6 @@ struct iwl_mvm_sta {
290 u8 max_agg_bufsize; 289 u8 max_agg_bufsize;
291 bool bt_reduced_txpower; 290 bool bt_reduced_txpower;
292 spinlock_t lock; 291 spinlock_t lock;
293 atomic_t pending_frames;
294 struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; 292 struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
295 struct iwl_lq_sta lq_sta; 293 struct iwl_lq_sta lq_sta;
296 struct ieee80211_vif *vif; 294 struct ieee80211_vif *vif;
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index 479074303bd7..f212f16502ff 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -416,9 +416,8 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
416 416
417 spin_unlock(&mvmsta->lock); 417 spin_unlock(&mvmsta->lock);
418 418
419 if (mvmsta->vif->type == NL80211_IFTYPE_AP && 419 if (txq_id < IWL_MVM_FIRST_AGG_QUEUE)
420 txq_id < IWL_MVM_FIRST_AGG_QUEUE) 420 atomic_inc(&mvm->pending_frames[mvmsta->sta_id]);
421 atomic_inc(&mvmsta->pending_frames);
422 421
423 return 0; 422 return 0;
424 423
@@ -680,16 +679,41 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
680 /* 679 /*
681 * If the txq is not an AMPDU queue, there is no chance we freed 680 * If the txq is not an AMPDU queue, there is no chance we freed
682 * several skbs. Check that out... 681 * several skbs. Check that out...
683 * If there are no pending frames for this STA, notify mac80211 that
684 * this station can go to sleep in its STA table.
685 */ 682 */
686 if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && mvmsta && 683 if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && !WARN_ON(skb_freed > 1) &&
687 !WARN_ON(skb_freed > 1) && 684 atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) {
688 mvmsta->vif->type == NL80211_IFTYPE_AP && 685 if (mvmsta) {
689 atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) { 686 /*
690 ieee80211_sta_block_awake(mvm->hw, sta, false); 687 * If there are no pending frames for this STA, notify
691 set_bit(sta_id, mvm->sta_drained); 688 * mac80211 that this station can go to sleep in its
692 schedule_work(&mvm->sta_drained_wk); 689 * STA table.
690 */
691 if (mvmsta->vif->type == NL80211_IFTYPE_AP)
692 ieee80211_sta_block_awake(mvm->hw, sta, false);
693 /*
694 * We might very well have taken mvmsta pointer while
695 * the station was being removed. The remove flow might
696 * have seen a pending_frame (because we didn't take
697 * the lock) even if now the queues are drained. So make
698 * really sure now that this the station is not being
699 * removed. If it is, run the drain worker to remove it.
700 */
701 spin_lock_bh(&mvmsta->lock);
702 sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
703 if (IS_ERR_OR_NULL(sta)) {
704 /*
705 * Station disappeared in the meantime:
706 * so we are draining.
707 */
708 set_bit(sta_id, mvm->sta_drained);
709 schedule_work(&mvm->sta_drained_wk);
710 }
711 spin_unlock_bh(&mvmsta->lock);
712 } else if (!mvmsta) {
713 /* Tx response without STA, so we are draining */
714 set_bit(sta_id, mvm->sta_drained);
715 schedule_work(&mvm->sta_drained_wk);
716 }
693 } 717 }
694 718
695 rcu_read_unlock(); 719 rcu_read_unlock();