diff options
author | Bob Copeland <me@bobcopeland.com> | 2015-01-09 14:15:52 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-01-23 12:12:12 -0500 |
commit | e26dc173a66ab3de38fbb8d71b58dbb72e29d6c9 (patch) | |
tree | e12750564432d803ce843ea53ea8d83a044342e3 /drivers/net/wireless | |
parent | 5f3f928585b22aada39f87611df75bac4a12a6c7 (diff) |
wcn36xx: initiate TX BA sessions
Currently, wcn36xx only asks for a TX BA session if it has
already established one for RX. Thus, two wcn36xx devices cannot
do a-mpdu between themselves since they both wait for the other
to go first. Fix this by starting a BA session after a few QoS
data frames have been sent to a STA.
Signed-off-by: Bob Copeland <me@bobcopeland.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/main.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/txrx.c | 45 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 20 |
3 files changed, 77 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 972bb3e653a1..0783d2ed8238 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c | |||
@@ -797,6 +797,7 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
797 | wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n", | 797 | wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n", |
798 | vif, sta->addr); | 798 | vif, sta->addr); |
799 | 799 | ||
800 | spin_lock_init(&sta_priv->ampdu_lock); | ||
800 | vif_priv->sta = sta_priv; | 801 | vif_priv->sta = sta_priv; |
801 | sta_priv->vif = vif_priv; | 802 | sta_priv->vif = vif_priv; |
802 | /* | 803 | /* |
@@ -875,21 +876,32 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, | |||
875 | get_sta_index(vif, sta_priv)); | 876 | get_sta_index(vif, sta_priv)); |
876 | wcn36xx_smd_add_ba(wcn); | 877 | wcn36xx_smd_add_ba(wcn); |
877 | wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv)); | 878 | wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv)); |
878 | ieee80211_start_tx_ba_session(sta, tid, 0); | ||
879 | break; | 879 | break; |
880 | case IEEE80211_AMPDU_RX_STOP: | 880 | case IEEE80211_AMPDU_RX_STOP: |
881 | wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv)); | 881 | wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv)); |
882 | break; | 882 | break; |
883 | case IEEE80211_AMPDU_TX_START: | 883 | case IEEE80211_AMPDU_TX_START: |
884 | spin_lock_bh(&sta_priv->ampdu_lock); | ||
885 | sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; | ||
886 | spin_unlock_bh(&sta_priv->ampdu_lock); | ||
887 | |||
884 | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | 888 | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
885 | break; | 889 | break; |
886 | case IEEE80211_AMPDU_TX_OPERATIONAL: | 890 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
891 | spin_lock_bh(&sta_priv->ampdu_lock); | ||
892 | sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL; | ||
893 | spin_unlock_bh(&sta_priv->ampdu_lock); | ||
894 | |||
887 | wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1, | 895 | wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1, |
888 | get_sta_index(vif, sta_priv)); | 896 | get_sta_index(vif, sta_priv)); |
889 | break; | 897 | break; |
890 | case IEEE80211_AMPDU_TX_STOP_FLUSH: | 898 | case IEEE80211_AMPDU_TX_STOP_FLUSH: |
891 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: | 899 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: |
892 | case IEEE80211_AMPDU_TX_STOP_CONT: | 900 | case IEEE80211_AMPDU_TX_STOP_CONT: |
901 | spin_lock_bh(&sta_priv->ampdu_lock); | ||
902 | sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE; | ||
903 | spin_unlock_bh(&sta_priv->ampdu_lock); | ||
904 | |||
893 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | 905 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
894 | break; | 906 | break; |
895 | default: | 907 | default: |
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 7f0d9e6afcec..9bec8237231d 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c | |||
@@ -111,6 +111,42 @@ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn, | |||
111 | wcn36xx_warn("vif %pM not found\n", addr); | 111 | wcn36xx_warn("vif %pM not found\n", addr); |
112 | return NULL; | 112 | return NULL; |
113 | } | 113 | } |
114 | |||
115 | static void wcn36xx_tx_start_ampdu(struct wcn36xx *wcn, | ||
116 | struct wcn36xx_sta *sta_priv, | ||
117 | struct sk_buff *skb) | ||
118 | { | ||
119 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
120 | struct ieee80211_sta *sta; | ||
121 | u8 *qc, tid; | ||
122 | |||
123 | if (!conf_is_ht(&wcn->hw->conf)) | ||
124 | return; | ||
125 | |||
126 | sta = wcn36xx_priv_to_sta(sta_priv); | ||
127 | |||
128 | if (WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) | ||
129 | return; | ||
130 | |||
131 | if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) | ||
132 | return; | ||
133 | |||
134 | qc = ieee80211_get_qos_ctl(hdr); | ||
135 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | ||
136 | |||
137 | spin_lock(&sta_priv->ampdu_lock); | ||
138 | if (sta_priv->ampdu_state[tid] != WCN36XX_AMPDU_NONE) | ||
139 | goto out_unlock; | ||
140 | |||
141 | if (sta_priv->non_agg_frame_ct++ >= WCN36XX_AMPDU_START_THRESH) { | ||
142 | sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; | ||
143 | sta_priv->non_agg_frame_ct = 0; | ||
144 | ieee80211_start_tx_ba_session(sta, tid, 0); | ||
145 | } | ||
146 | out_unlock: | ||
147 | spin_unlock(&sta_priv->ampdu_lock); | ||
148 | } | ||
149 | |||
114 | static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, | 150 | static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, |
115 | struct wcn36xx *wcn, | 151 | struct wcn36xx *wcn, |
116 | struct wcn36xx_vif **vif_priv, | 152 | struct wcn36xx_vif **vif_priv, |
@@ -121,6 +157,8 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, | |||
121 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 157 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
122 | struct ieee80211_vif *vif = NULL; | 158 | struct ieee80211_vif *vif = NULL; |
123 | struct wcn36xx_vif *__vif_priv = NULL; | 159 | struct wcn36xx_vif *__vif_priv = NULL; |
160 | bool is_data_qos; | ||
161 | |||
124 | bd->bd_rate = WCN36XX_BD_RATE_DATA; | 162 | bd->bd_rate = WCN36XX_BD_RATE_DATA; |
125 | 163 | ||
126 | /* | 164 | /* |
@@ -160,11 +198,16 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, | |||
160 | } | 198 | } |
161 | *vif_priv = __vif_priv; | 199 | *vif_priv = __vif_priv; |
162 | 200 | ||
201 | is_data_qos = ieee80211_is_data_qos(hdr->frame_control); | ||
202 | |||
163 | wcn36xx_set_tx_pdu(bd, | 203 | wcn36xx_set_tx_pdu(bd, |
164 | ieee80211_is_data_qos(hdr->frame_control) ? | 204 | is_data_qos ? |
165 | sizeof(struct ieee80211_qos_hdr) : | 205 | sizeof(struct ieee80211_qos_hdr) : |
166 | sizeof(struct ieee80211_hdr_3addr), | 206 | sizeof(struct ieee80211_hdr_3addr), |
167 | skb->len, sta_priv ? sta_priv->tid : 0); | 207 | skb->len, sta_priv ? sta_priv->tid : 0); |
208 | |||
209 | if (sta_priv && is_data_qos) | ||
210 | wcn36xx_tx_start_ampdu(wcn, sta_priv, skb); | ||
168 | } | 211 | } |
169 | 212 | ||
170 | static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd, | 213 | static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd, |
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index f0fb81dfd17b..7b41e833e18c 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h | |||
@@ -32,6 +32,9 @@ | |||
32 | #define WLAN_NV_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" | 32 | #define WLAN_NV_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" |
33 | #define WCN36XX_AGGR_BUFFER_SIZE 64 | 33 | #define WCN36XX_AGGR_BUFFER_SIZE 64 |
34 | 34 | ||
35 | /* How many frames until we start a-mpdu TX session */ | ||
36 | #define WCN36XX_AMPDU_START_THRESH 20 | ||
37 | |||
35 | extern unsigned int wcn36xx_dbg_mask; | 38 | extern unsigned int wcn36xx_dbg_mask; |
36 | 39 | ||
37 | enum wcn36xx_debug_mask { | 40 | enum wcn36xx_debug_mask { |
@@ -74,6 +77,13 @@ enum wcn36xx_debug_mask { | |||
74 | buf, len, false); \ | 77 | buf, len, false); \ |
75 | } while (0) | 78 | } while (0) |
76 | 79 | ||
80 | enum wcn36xx_ampdu_state { | ||
81 | WCN36XX_AMPDU_NONE, | ||
82 | WCN36XX_AMPDU_INIT, | ||
83 | WCN36XX_AMPDU_START, | ||
84 | WCN36XX_AMPDU_OPERATIONAL, | ||
85 | }; | ||
86 | |||
77 | #define WCN36XX_HW_CHANNEL(__wcn) (__wcn->hw->conf.chandef.chan->hw_value) | 87 | #define WCN36XX_HW_CHANNEL(__wcn) (__wcn->hw->conf.chandef.chan->hw_value) |
78 | #define WCN36XX_BAND(__wcn) (__wcn->hw->conf.chandef.chan->band) | 88 | #define WCN36XX_BAND(__wcn) (__wcn->hw->conf.chandef.chan->band) |
79 | #define WCN36XX_CENTER_FREQ(__wcn) (__wcn->hw->conf.chandef.chan->center_freq) | 89 | #define WCN36XX_CENTER_FREQ(__wcn) (__wcn->hw->conf.chandef.chan->center_freq) |
@@ -165,6 +175,10 @@ struct wcn36xx_sta { | |||
165 | bool is_data_encrypted; | 175 | bool is_data_encrypted; |
166 | /* Rates */ | 176 | /* Rates */ |
167 | struct wcn36xx_hal_supported_rates supported_rates; | 177 | struct wcn36xx_hal_supported_rates supported_rates; |
178 | |||
179 | spinlock_t ampdu_lock; /* protects next two fields */ | ||
180 | enum wcn36xx_ampdu_state ampdu_state[16]; | ||
181 | int non_agg_frame_ct; | ||
168 | }; | 182 | }; |
169 | struct wcn36xx_dxe_ch; | 183 | struct wcn36xx_dxe_ch; |
170 | struct wcn36xx { | 184 | struct wcn36xx { |
@@ -243,4 +257,10 @@ static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn, | |||
243 | } | 257 | } |
244 | void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates); | 258 | void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates); |
245 | 259 | ||
260 | static inline | ||
261 | struct ieee80211_sta *wcn36xx_priv_to_sta(struct wcn36xx_sta *sta_priv) | ||
262 | { | ||
263 | return container_of((void *)sta_priv, struct ieee80211_sta, drv_priv); | ||
264 | } | ||
265 | |||
246 | #endif /* _WCN36XX_H_ */ | 266 | #endif /* _WCN36XX_H_ */ |