diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/sta.c | 213 |
1 files changed, 162 insertions, 51 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 3397f59cd4e4..f339ef884250 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -66,27 +66,27 @@ | |||
66 | #include "sta.h" | 66 | #include "sta.h" |
67 | #include "rs.h" | 67 | #include "rs.h" |
68 | 68 | ||
69 | static void iwl_mvm_add_sta_cmd_v6_to_v5(struct iwl_mvm_add_sta_cmd_v6 *cmd_v6, | 69 | static void iwl_mvm_add_sta_cmd_v7_to_v5(struct iwl_mvm_add_sta_cmd_v7 *cmd_v7, |
70 | struct iwl_mvm_add_sta_cmd_v5 *cmd_v5) | 70 | struct iwl_mvm_add_sta_cmd_v5 *cmd_v5) |
71 | { | 71 | { |
72 | memset(cmd_v5, 0, sizeof(*cmd_v5)); | 72 | memset(cmd_v5, 0, sizeof(*cmd_v5)); |
73 | 73 | ||
74 | cmd_v5->add_modify = cmd_v6->add_modify; | 74 | cmd_v5->add_modify = cmd_v7->add_modify; |
75 | cmd_v5->tid_disable_tx = cmd_v6->tid_disable_tx; | 75 | cmd_v5->tid_disable_tx = cmd_v7->tid_disable_tx; |
76 | cmd_v5->mac_id_n_color = cmd_v6->mac_id_n_color; | 76 | cmd_v5->mac_id_n_color = cmd_v7->mac_id_n_color; |
77 | memcpy(cmd_v5->addr, cmd_v6->addr, ETH_ALEN); | 77 | memcpy(cmd_v5->addr, cmd_v7->addr, ETH_ALEN); |
78 | cmd_v5->sta_id = cmd_v6->sta_id; | 78 | cmd_v5->sta_id = cmd_v7->sta_id; |
79 | cmd_v5->modify_mask = cmd_v6->modify_mask; | 79 | cmd_v5->modify_mask = cmd_v7->modify_mask; |
80 | cmd_v5->station_flags = cmd_v6->station_flags; | 80 | cmd_v5->station_flags = cmd_v7->station_flags; |
81 | cmd_v5->station_flags_msk = cmd_v6->station_flags_msk; | 81 | cmd_v5->station_flags_msk = cmd_v7->station_flags_msk; |
82 | cmd_v5->add_immediate_ba_tid = cmd_v6->add_immediate_ba_tid; | 82 | cmd_v5->add_immediate_ba_tid = cmd_v7->add_immediate_ba_tid; |
83 | cmd_v5->remove_immediate_ba_tid = cmd_v6->remove_immediate_ba_tid; | 83 | cmd_v5->remove_immediate_ba_tid = cmd_v7->remove_immediate_ba_tid; |
84 | cmd_v5->add_immediate_ba_ssn = cmd_v6->add_immediate_ba_ssn; | 84 | cmd_v5->add_immediate_ba_ssn = cmd_v7->add_immediate_ba_ssn; |
85 | cmd_v5->sleep_tx_count = cmd_v6->sleep_tx_count; | 85 | cmd_v5->sleep_tx_count = cmd_v7->sleep_tx_count; |
86 | cmd_v5->sleep_state_flags = cmd_v6->sleep_state_flags; | 86 | cmd_v5->sleep_state_flags = cmd_v7->sleep_state_flags; |
87 | cmd_v5->assoc_id = cmd_v6->assoc_id; | 87 | cmd_v5->assoc_id = cmd_v7->assoc_id; |
88 | cmd_v5->beamform_flags = cmd_v6->beamform_flags; | 88 | cmd_v5->beamform_flags = cmd_v7->beamform_flags; |
89 | cmd_v5->tfd_queue_msk = cmd_v6->tfd_queue_msk; | 89 | cmd_v5->tfd_queue_msk = cmd_v7->tfd_queue_msk; |
90 | } | 90 | } |
91 | 91 | ||
92 | static void | 92 | static void |
@@ -110,7 +110,7 @@ iwl_mvm_add_sta_key_to_add_sta_cmd_v5(struct iwl_mvm_add_sta_key_cmd *key_cmd, | |||
110 | } | 110 | } |
111 | 111 | ||
112 | static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm, | 112 | static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm, |
113 | struct iwl_mvm_add_sta_cmd_v6 *cmd, | 113 | struct iwl_mvm_add_sta_cmd_v7 *cmd, |
114 | int *status) | 114 | int *status) |
115 | { | 115 | { |
116 | struct iwl_mvm_add_sta_cmd_v5 cmd_v5; | 116 | struct iwl_mvm_add_sta_cmd_v5 cmd_v5; |
@@ -119,14 +119,14 @@ static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm, | |||
119 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd), | 119 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd), |
120 | cmd, status); | 120 | cmd, status); |
121 | 121 | ||
122 | iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5); | 122 | iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5); |
123 | 123 | ||
124 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5), | 124 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5), |
125 | &cmd_v5, status); | 125 | &cmd_v5, status); |
126 | } | 126 | } |
127 | 127 | ||
128 | static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, | 128 | static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, |
129 | struct iwl_mvm_add_sta_cmd_v6 *cmd) | 129 | struct iwl_mvm_add_sta_cmd_v7 *cmd) |
130 | { | 130 | { |
131 | struct iwl_mvm_add_sta_cmd_v5 cmd_v5; | 131 | struct iwl_mvm_add_sta_cmd_v5 cmd_v5; |
132 | 132 | ||
@@ -134,7 +134,7 @@ static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, | |||
134 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, | 134 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, |
135 | sizeof(*cmd), cmd); | 135 | sizeof(*cmd), cmd); |
136 | 136 | ||
137 | iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5); | 137 | iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5); |
138 | 138 | ||
139 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5), | 139 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5), |
140 | &cmd_v5); | 140 | &cmd_v5); |
@@ -175,19 +175,30 @@ static int iwl_mvm_send_add_sta_key_cmd(struct iwl_mvm *mvm, | |||
175 | &sta_cmd); | 175 | &sta_cmd); |
176 | } | 176 | } |
177 | 177 | ||
178 | static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) | 178 | static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, |
179 | enum nl80211_iftype iftype) | ||
179 | { | 180 | { |
180 | int sta_id; | 181 | int sta_id; |
182 | u32 reserved_ids = 0; | ||
181 | 183 | ||
184 | BUILD_BUG_ON(IWL_MVM_STATION_COUNT > 32); | ||
182 | WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)); | 185 | WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)); |
183 | 186 | ||
184 | lockdep_assert_held(&mvm->mutex); | 187 | lockdep_assert_held(&mvm->mutex); |
185 | 188 | ||
189 | /* d0i3/d3 assumes the AP's sta_id (of sta vif) is 0. reserve it. */ | ||
190 | if (iftype != NL80211_IFTYPE_STATION) | ||
191 | reserved_ids = BIT(0); | ||
192 | |||
186 | /* Don't take rcu_read_lock() since we are protected by mvm->mutex */ | 193 | /* Don't take rcu_read_lock() since we are protected by mvm->mutex */ |
187 | for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) | 194 | for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) { |
195 | if (BIT(sta_id) & reserved_ids) | ||
196 | continue; | ||
197 | |||
188 | if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | 198 | if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], |
189 | lockdep_is_held(&mvm->mutex))) | 199 | lockdep_is_held(&mvm->mutex))) |
190 | return sta_id; | 200 | return sta_id; |
201 | } | ||
191 | return IWL_MVM_STATION_COUNT; | 202 | return IWL_MVM_STATION_COUNT; |
192 | } | 203 | } |
193 | 204 | ||
@@ -196,7 +207,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
196 | bool update) | 207 | bool update) |
197 | { | 208 | { |
198 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 209 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
199 | struct iwl_mvm_add_sta_cmd_v6 add_sta_cmd; | 210 | struct iwl_mvm_add_sta_cmd_v7 add_sta_cmd; |
200 | int ret; | 211 | int ret; |
201 | u32 status; | 212 | u32 status; |
202 | u32 agg_size = 0, mpdu_dens = 0; | 213 | u32 agg_size = 0, mpdu_dens = 0; |
@@ -312,7 +323,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
312 | lockdep_assert_held(&mvm->mutex); | 323 | lockdep_assert_held(&mvm->mutex); |
313 | 324 | ||
314 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | 325 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) |
315 | sta_id = iwl_mvm_find_free_sta_id(mvm); | 326 | sta_id = iwl_mvm_find_free_sta_id(mvm, |
327 | ieee80211_vif_type_p2p(vif)); | ||
316 | else | 328 | else |
317 | sta_id = mvm_sta->sta_id; | 329 | sta_id = mvm_sta->sta_id; |
318 | 330 | ||
@@ -368,7 +380,7 @@ int iwl_mvm_update_sta(struct iwl_mvm *mvm, | |||
368 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | 380 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, |
369 | bool drain) | 381 | bool drain) |
370 | { | 382 | { |
371 | struct iwl_mvm_add_sta_cmd_v6 cmd = {}; | 383 | struct iwl_mvm_add_sta_cmd_v7 cmd = {}; |
372 | int ret; | 384 | int ret; |
373 | u32 status; | 385 | u32 status; |
374 | 386 | ||
@@ -522,6 +534,10 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | |||
522 | 534 | ||
523 | /* unassoc - go ahead - remove the AP STA now */ | 535 | /* unassoc - go ahead - remove the AP STA now */ |
524 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | 536 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; |
537 | |||
538 | /* clear d0i3_ap_sta_id if no longer relevant */ | ||
539 | if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id) | ||
540 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
525 | } | 541 | } |
526 | 542 | ||
527 | /* | 543 | /* |
@@ -560,10 +576,10 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, | |||
560 | } | 576 | } |
561 | 577 | ||
562 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, | 578 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, |
563 | u32 qmask) | 579 | u32 qmask, enum nl80211_iftype iftype) |
564 | { | 580 | { |
565 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | 581 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { |
566 | sta->sta_id = iwl_mvm_find_free_sta_id(mvm); | 582 | sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); |
567 | if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT)) | 583 | if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT)) |
568 | return -ENOSPC; | 584 | return -ENOSPC; |
569 | } | 585 | } |
@@ -587,13 +603,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, | |||
587 | const u8 *addr, | 603 | const u8 *addr, |
588 | u16 mac_id, u16 color) | 604 | u16 mac_id, u16 color) |
589 | { | 605 | { |
590 | struct iwl_mvm_add_sta_cmd_v6 cmd; | 606 | struct iwl_mvm_add_sta_cmd_v7 cmd; |
591 | int ret; | 607 | int ret; |
592 | u32 status; | 608 | u32 status; |
593 | 609 | ||
594 | lockdep_assert_held(&mvm->mutex); | 610 | lockdep_assert_held(&mvm->mutex); |
595 | 611 | ||
596 | memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v6)); | 612 | memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v7)); |
597 | cmd.sta_id = sta->sta_id; | 613 | cmd.sta_id = sta->sta_id; |
598 | cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, | 614 | cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, |
599 | color)); | 615 | color)); |
@@ -627,7 +643,8 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) | |||
627 | lockdep_assert_held(&mvm->mutex); | 643 | lockdep_assert_held(&mvm->mutex); |
628 | 644 | ||
629 | /* Add the aux station, but without any queues */ | 645 | /* Add the aux station, but without any queues */ |
630 | ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0); | 646 | ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0, |
647 | NL80211_IFTYPE_UNSPECIFIED); | ||
631 | if (ret) | 648 | if (ret) |
632 | return ret; | 649 | return ret; |
633 | 650 | ||
@@ -699,7 +716,8 @@ int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
699 | lockdep_assert_held(&mvm->mutex); | 716 | lockdep_assert_held(&mvm->mutex); |
700 | 717 | ||
701 | qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); | 718 | qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); |
702 | ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask); | 719 | ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask, |
720 | ieee80211_vif_type_p2p(vif)); | ||
703 | if (ret) | 721 | if (ret) |
704 | return ret; | 722 | return ret; |
705 | 723 | ||
@@ -735,7 +753,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
735 | int tid, u16 ssn, bool start) | 753 | int tid, u16 ssn, bool start) |
736 | { | 754 | { |
737 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 755 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
738 | struct iwl_mvm_add_sta_cmd_v6 cmd = {}; | 756 | struct iwl_mvm_add_sta_cmd_v7 cmd = {}; |
739 | int ret; | 757 | int ret; |
740 | u32 status; | 758 | u32 status; |
741 | 759 | ||
@@ -794,7 +812,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
794 | int tid, u8 queue, bool start) | 812 | int tid, u8 queue, bool start) |
795 | { | 813 | { |
796 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 814 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
797 | struct iwl_mvm_add_sta_cmd_v6 cmd = {}; | 815 | struct iwl_mvm_add_sta_cmd_v7 cmd = {}; |
798 | int ret; | 816 | int ret; |
799 | u32 status; | 817 | u32 status; |
800 | 818 | ||
@@ -833,7 +851,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
833 | return ret; | 851 | return ret; |
834 | } | 852 | } |
835 | 853 | ||
836 | static const u8 tid_to_ac[] = { | 854 | const u8 tid_to_mac80211_ac[] = { |
837 | IEEE80211_AC_BE, | 855 | IEEE80211_AC_BE, |
838 | IEEE80211_AC_BK, | 856 | IEEE80211_AC_BK, |
839 | IEEE80211_AC_BK, | 857 | IEEE80211_AC_BK, |
@@ -844,6 +862,17 @@ static const u8 tid_to_ac[] = { | |||
844 | IEEE80211_AC_VO, | 862 | IEEE80211_AC_VO, |
845 | }; | 863 | }; |
846 | 864 | ||
865 | static const u8 tid_to_ucode_ac[] = { | ||
866 | AC_BE, | ||
867 | AC_BK, | ||
868 | AC_BK, | ||
869 | AC_BE, | ||
870 | AC_VI, | ||
871 | AC_VI, | ||
872 | AC_VO, | ||
873 | AC_VO, | ||
874 | }; | ||
875 | |||
847 | int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 876 | int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
848 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) | 877 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) |
849 | { | 878 | { |
@@ -873,10 +902,18 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
873 | return -EIO; | 902 | return -EIO; |
874 | } | 903 | } |
875 | 904 | ||
905 | spin_lock_bh(&mvmsta->lock); | ||
906 | |||
907 | /* possible race condition - we entered D0i3 while starting agg */ | ||
908 | if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)) { | ||
909 | spin_unlock_bh(&mvmsta->lock); | ||
910 | IWL_ERR(mvm, "Entered D0i3 while starting Tx agg\n"); | ||
911 | return -EIO; | ||
912 | } | ||
913 | |||
876 | /* the new tx queue is still connected to the same mac80211 queue */ | 914 | /* the new tx queue is still connected to the same mac80211 queue */ |
877 | mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_ac[tid]]; | 915 | mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_mac80211_ac[tid]]; |
878 | 916 | ||
879 | spin_lock_bh(&mvmsta->lock); | ||
880 | tid_data = &mvmsta->tid_data[tid]; | 917 | tid_data = &mvmsta->tid_data[tid]; |
881 | tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); | 918 | tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); |
882 | tid_data->txq_id = txq_id; | 919 | tid_data->txq_id = txq_id; |
@@ -916,7 +953,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
916 | tid_data->ssn = 0xffff; | 953 | tid_data->ssn = 0xffff; |
917 | spin_unlock_bh(&mvmsta->lock); | 954 | spin_unlock_bh(&mvmsta->lock); |
918 | 955 | ||
919 | fifo = iwl_mvm_ac_to_tx_fifo[tid_to_ac[tid]]; | 956 | fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; |
920 | 957 | ||
921 | ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); | 958 | ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); |
922 | if (ret) | 959 | if (ret) |
@@ -1411,7 +1448,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, | |||
1411 | struct ieee80211_sta *sta) | 1448 | struct ieee80211_sta *sta) |
1412 | { | 1449 | { |
1413 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | 1450 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1414 | struct iwl_mvm_add_sta_cmd_v6 cmd = { | 1451 | struct iwl_mvm_add_sta_cmd_v7 cmd = { |
1415 | .add_modify = STA_MODE_MODIFY, | 1452 | .add_modify = STA_MODE_MODIFY, |
1416 | .sta_id = mvmsta->sta_id, | 1453 | .sta_id = mvmsta->sta_id, |
1417 | .station_flags_msk = cpu_to_le32(STA_FLG_PS), | 1454 | .station_flags_msk = cpu_to_le32(STA_FLG_PS), |
@@ -1427,28 +1464,102 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, | |||
1427 | void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, | 1464 | void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, |
1428 | struct ieee80211_sta *sta, | 1465 | struct ieee80211_sta *sta, |
1429 | enum ieee80211_frame_release_type reason, | 1466 | enum ieee80211_frame_release_type reason, |
1430 | u16 cnt) | 1467 | u16 cnt, u16 tids, bool more_data, |
1468 | bool agg) | ||
1431 | { | 1469 | { |
1432 | u16 sleep_state_flags = | ||
1433 | (reason == IEEE80211_FRAME_RELEASE_UAPSD) ? | ||
1434 | STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL; | ||
1435 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | 1470 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1436 | struct iwl_mvm_add_sta_cmd_v6 cmd = { | 1471 | struct iwl_mvm_add_sta_cmd_v7 cmd = { |
1437 | .add_modify = STA_MODE_MODIFY, | 1472 | .add_modify = STA_MODE_MODIFY, |
1438 | .sta_id = mvmsta->sta_id, | 1473 | .sta_id = mvmsta->sta_id, |
1439 | .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, | 1474 | .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, |
1440 | .sleep_tx_count = cpu_to_le16(cnt), | 1475 | .sleep_tx_count = cpu_to_le16(cnt), |
1441 | .mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color), | 1476 | .mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color), |
1442 | /* | ||
1443 | * Same modify mask for sleep_tx_count and sleep_state_flags so | ||
1444 | * we must set the sleep_state_flags too. | ||
1445 | */ | ||
1446 | .sleep_state_flags = cpu_to_le16(sleep_state_flags), | ||
1447 | }; | 1477 | }; |
1448 | int ret; | 1478 | int tid, ret; |
1479 | unsigned long _tids = tids; | ||
1480 | |||
1481 | /* convert TIDs to ACs - we don't support TSPEC so that's OK | ||
1482 | * Note that this field is reserved and unused by firmware not | ||
1483 | * supporting GO uAPSD, so it's safe to always do this. | ||
1484 | */ | ||
1485 | for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) | ||
1486 | cmd.awake_acs |= BIT(tid_to_ucode_ac[tid]); | ||
1487 | |||
1488 | /* If we're releasing frames from aggregation queues then check if the | ||
1489 | * all queues combined that we're releasing frames from have | ||
1490 | * - more frames than the service period, in which case more_data | ||
1491 | * needs to be set | ||
1492 | * - fewer than 'cnt' frames, in which case we need to adjust the | ||
1493 | * firmware command (but do that unconditionally) | ||
1494 | */ | ||
1495 | if (agg) { | ||
1496 | int remaining = cnt; | ||
1497 | |||
1498 | spin_lock_bh(&mvmsta->lock); | ||
1499 | for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) { | ||
1500 | struct iwl_mvm_tid_data *tid_data; | ||
1501 | u16 n_queued; | ||
1502 | |||
1503 | tid_data = &mvmsta->tid_data[tid]; | ||
1504 | if (WARN(tid_data->state != IWL_AGG_ON && | ||
1505 | tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA, | ||
1506 | "TID %d state is %d\n", | ||
1507 | tid, tid_data->state)) { | ||
1508 | spin_unlock_bh(&mvmsta->lock); | ||
1509 | ieee80211_sta_eosp(sta); | ||
1510 | return; | ||
1511 | } | ||
1512 | |||
1513 | n_queued = iwl_mvm_tid_queued(tid_data); | ||
1514 | if (n_queued > remaining) { | ||
1515 | more_data = true; | ||
1516 | remaining = 0; | ||
1517 | break; | ||
1518 | } | ||
1519 | remaining -= n_queued; | ||
1520 | } | ||
1521 | spin_unlock_bh(&mvmsta->lock); | ||
1522 | |||
1523 | cmd.sleep_tx_count = cpu_to_le16(cnt - remaining); | ||
1524 | if (WARN_ON(cnt - remaining == 0)) { | ||
1525 | ieee80211_sta_eosp(sta); | ||
1526 | return; | ||
1527 | } | ||
1528 | } | ||
1529 | |||
1530 | /* Note: this is ignored by firmware not supporting GO uAPSD */ | ||
1531 | if (more_data) | ||
1532 | cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_MOREDATA); | ||
1533 | |||
1534 | if (reason == IEEE80211_FRAME_RELEASE_PSPOLL) { | ||
1535 | mvmsta->next_status_eosp = true; | ||
1536 | cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_PS_POLL); | ||
1537 | } else { | ||
1538 | cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_UAPSD); | ||
1539 | } | ||
1449 | 1540 | ||
1450 | /* TODO: somehow the fw doesn't seem to take PS_POLL into account */ | ||
1451 | ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd); | 1541 | ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd); |
1452 | if (ret) | 1542 | if (ret) |
1453 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); | 1543 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); |
1454 | } | 1544 | } |
1545 | |||
1546 | int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, | ||
1547 | struct iwl_rx_cmd_buffer *rxb, | ||
1548 | struct iwl_device_cmd *cmd) | ||
1549 | { | ||
1550 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1551 | struct iwl_mvm_eosp_notification *notif = (void *)pkt->data; | ||
1552 | struct ieee80211_sta *sta; | ||
1553 | u32 sta_id = le32_to_cpu(notif->sta_id); | ||
1554 | |||
1555 | if (WARN_ON_ONCE(sta_id >= IWL_MVM_STATION_COUNT)) | ||
1556 | return 0; | ||
1557 | |||
1558 | rcu_read_lock(); | ||
1559 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
1560 | if (!IS_ERR_OR_NULL(sta)) | ||
1561 | ieee80211_sta_eosp(sta); | ||
1562 | rcu_read_unlock(); | ||
1563 | |||
1564 | return 0; | ||
1565 | } | ||