aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorBob Copeland <me@bobcopeland.com>2015-01-09 14:15:52 -0500
committerKalle Valo <kvalo@codeaurora.org>2015-01-23 12:12:12 -0500
commite26dc173a66ab3de38fbb8d71b58dbb72e29d6c9 (patch)
treee12750564432d803ce843ea53ea8d83a044342e3 /drivers/net/wireless
parent5f3f928585b22aada39f87611df75bac4a12a6c7 (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.c14
-rw-r--r--drivers/net/wireless/ath/wcn36xx/txrx.c45
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h20
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
115static 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 }
146out_unlock:
147 spin_unlock(&sta_priv->ampdu_lock);
148}
149
114static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, 150static 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
170static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd, 213static 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
35extern unsigned int wcn36xx_dbg_mask; 38extern unsigned int wcn36xx_dbg_mask;
36 39
37enum wcn36xx_debug_mask { 40enum 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
80enum 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};
169struct wcn36xx_dxe_ch; 183struct wcn36xx_dxe_ch;
170struct wcn36xx { 184struct wcn36xx {
@@ -243,4 +257,10 @@ static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn,
243} 257}
244void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates); 258void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates);
245 259
260static inline
261struct 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_ */