|
@@ -111,6 +111,42 @@ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
|
|
|
wcn36xx_warn("vif %pM not found\n", addr);
|
|
|
return NULL;
|
|
|
}
|
|
|
+
|
|
|
+static void wcn36xx_tx_start_ampdu(struct wcn36xx *wcn,
|
|
|
+ struct wcn36xx_sta *sta_priv,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
+ struct ieee80211_sta *sta;
|
|
|
+ u8 *qc, tid;
|
|
|
+
|
|
|
+ if (!conf_is_ht(&wcn->hw->conf))
|
|
|
+ return;
|
|
|
+
|
|
|
+ sta = wcn36xx_priv_to_sta(sta_priv);
|
|
|
+
|
|
|
+ if (WARN_ON(!ieee80211_is_data_qos(hdr->frame_control)))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
|
|
|
+ return;
|
|
|
+
|
|
|
+ qc = ieee80211_get_qos_ctl(hdr);
|
|
|
+ tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
|
|
|
+
|
|
|
+ spin_lock(&sta_priv->ampdu_lock);
|
|
|
+ if (sta_priv->ampdu_state[tid] != WCN36XX_AMPDU_NONE)
|
|
|
+ goto out_unlock;
|
|
|
+
|
|
|
+ if (sta_priv->non_agg_frame_ct++ >= WCN36XX_AMPDU_START_THRESH) {
|
|
|
+ sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
|
|
|
+ sta_priv->non_agg_frame_ct = 0;
|
|
|
+ ieee80211_start_tx_ba_session(sta, tid, 0);
|
|
|
+ }
|
|
|
+out_unlock:
|
|
|
+ spin_unlock(&sta_priv->ampdu_lock);
|
|
|
+}
|
|
|
+
|
|
|
static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
|
|
|
struct wcn36xx *wcn,
|
|
|
struct wcn36xx_vif **vif_priv,
|
|
@@ -121,6 +157,8 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
struct ieee80211_vif *vif = NULL;
|
|
|
struct wcn36xx_vif *__vif_priv = NULL;
|
|
|
+ bool is_data_qos;
|
|
|
+
|
|
|
bd->bd_rate = WCN36XX_BD_RATE_DATA;
|
|
|
|
|
|
/*
|
|
@@ -160,11 +198,16 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
|
|
|
}
|
|
|
*vif_priv = __vif_priv;
|
|
|
|
|
|
+ is_data_qos = ieee80211_is_data_qos(hdr->frame_control);
|
|
|
+
|
|
|
wcn36xx_set_tx_pdu(bd,
|
|
|
- ieee80211_is_data_qos(hdr->frame_control) ?
|
|
|
+ is_data_qos ?
|
|
|
sizeof(struct ieee80211_qos_hdr) :
|
|
|
sizeof(struct ieee80211_hdr_3addr),
|
|
|
skb->len, sta_priv ? sta_priv->tid : 0);
|
|
|
+
|
|
|
+ if (sta_priv && is_data_qos)
|
|
|
+ wcn36xx_tx_start_ampdu(wcn, sta_priv, skb);
|
|
|
}
|
|
|
|
|
|
static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
|