aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-10-26 10:00:29 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2016-02-27 15:00:01 -0500
commitbb81bb68f472bb0f9afbb483259d91d4efd86bfb (patch)
tree9885a84948a24719c515ccdb27d64ad8a25157b1 /drivers/net/wireless/intel
parenta6d5e32f247cbd3e34c7f86effbf4b426a018c32 (diff)
iwlwifi: mvm: add Tx A-MSDU inside A-MPDU
If the peer allows, we can have A-MSDU inside A-MDPU. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/intel')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c37
4 files changed, 38 insertions, 12 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index f1ed90bc2740..1a4946fc9b27 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -847,6 +847,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
847 u16 tid = params->tid; 847 u16 tid = params->tid;
848 u16 *ssn = &params->ssn; 848 u16 *ssn = &params->ssn;
849 u8 buf_size = params->buf_size; 849 u8 buf_size = params->buf_size;
850 bool amsdu = params->amsdu;
850 851
851 IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n", 852 IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
852 sta->addr, tid, action); 853 sta->addr, tid, action);
@@ -907,7 +908,8 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
907 ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid); 908 ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid);
908 break; 909 break;
909 case IEEE80211_AMPDU_TX_OPERATIONAL: 910 case IEEE80211_AMPDU_TX_OPERATIONAL:
910 ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size); 911 ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid,
912 buf_size, amsdu);
911 break; 913 break;
912 default: 914 default:
913 WARN_ON_ONCE(1); 915 WARN_ON_ONCE(1);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 4854e79cbda8..b2123ce3e3a8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1031,7 +1031,8 @@ release_locks:
1031} 1031}
1032 1032
1033int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 1033int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1034 struct ieee80211_sta *sta, u16 tid, u8 buf_size) 1034 struct ieee80211_sta *sta, u16 tid, u8 buf_size,
1035 bool amsdu)
1035{ 1036{
1036 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 1037 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1037 struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; 1038 struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
@@ -1051,6 +1052,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1051 tid_data->state = IWL_AGG_ON; 1052 tid_data->state = IWL_AGG_ON;
1052 mvmsta->agg_tids |= BIT(tid); 1053 mvmsta->agg_tids |= BIT(tid);
1053 tid_data->ssn = 0xffff; 1054 tid_data->ssn = 0xffff;
1055 tid_data->amsdu_in_ampdu_allowed = amsdu;
1054 spin_unlock_bh(&mvmsta->lock); 1056 spin_unlock_bh(&mvmsta->lock);
1055 1057
1056 fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; 1058 fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index e3b9446ee995..b01650ac3598 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -260,6 +260,7 @@ enum iwl_mvm_agg_state {
260 * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA). 260 * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA).
261 * @reduced_tpc: Reduced tx power. Holds the data between the 261 * @reduced_tpc: Reduced tx power. Holds the data between the
262 * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA). 262 * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA).
263 * @amsdu_in_ampdu_allowed: true if A-MSDU in A-MPDU is allowed.
263 * @state: state of the BA agreement establishment / tear down. 264 * @state: state of the BA agreement establishment / tear down.
264 * @txq_id: Tx queue used by the BA session 265 * @txq_id: Tx queue used by the BA session
265 * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or 266 * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or
@@ -274,6 +275,7 @@ struct iwl_mvm_tid_data {
274 /* The rest is Tx AGG related */ 275 /* The rest is Tx AGG related */
275 u32 rate_n_flags; 276 u32 rate_n_flags;
276 u8 reduced_tpc; 277 u8 reduced_tpc;
278 bool amsdu_in_ampdu_allowed;
277 enum iwl_mvm_agg_state state; 279 enum iwl_mvm_agg_state state;
278 u16 txq_id; 280 u16 txq_id;
279 u16 ssn; 281 u16 ssn;
@@ -405,7 +407,8 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
405int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 407int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
406 struct ieee80211_sta *sta, u16 tid, u16 *ssn); 408 struct ieee80211_sta *sta, u16 tid, u16 *ssn);
407int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 409int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
408 struct ieee80211_sta *sta, u16 tid, u8 buf_size); 410 struct ieee80211_sta *sta, u16 tid, u8 buf_size,
411 bool amsdu);
409int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 412int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
410 struct ieee80211_sta *sta, u16 tid); 413 struct ieee80211_sta *sta, u16 tid);
411int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 414int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 6f67de5a2858..ff08b17b76dd 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -438,19 +438,26 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
438 struct ieee80211_sta *sta, 438 struct ieee80211_sta *sta,
439 struct sk_buff_head *mpdus_skb) 439 struct sk_buff_head *mpdus_skb)
440{ 440{
441 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
441 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 442 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
442 struct ieee80211_hdr *hdr = (void *)skb->data; 443 struct ieee80211_hdr *hdr = (void *)skb->data;
443 unsigned int mss = skb_shinfo(skb)->gso_size; 444 unsigned int mss = skb_shinfo(skb)->gso_size;
444 struct sk_buff *tmp, *next; 445 struct sk_buff *tmp, *next;
445 char cb[sizeof(skb->cb)]; 446 char cb[sizeof(skb->cb)];
446 unsigned int num_subframes, tcp_payload_len, subf_len; 447 unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len;
447 bool ipv4 = (skb->protocol == htons(ETH_P_IP)); 448 bool ipv4 = (skb->protocol == htons(ETH_P_IP));
448 u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0; 449 u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
449 u16 amsdu_add, snap_ip_tcp, pad, i = 0; 450 u16 amsdu_add, snap_ip_tcp, pad, i = 0;
451 u8 *qc, tid;
450 452
451 snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) + 453 snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) +
452 tcp_hdrlen(skb); 454 tcp_hdrlen(skb);
453 455
456 qc = ieee80211_get_qos_ctl(hdr);
457 tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
458 if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
459 return -EINVAL;
460
454 if (!sta->max_amsdu_len || 461 if (!sta->max_amsdu_len ||
455 !ieee80211_is_data_qos(hdr->frame_control)) { 462 !ieee80211_is_data_qos(hdr->frame_control)) {
456 num_subframes = 1; 463 num_subframes = 1;
@@ -458,13 +465,28 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
458 goto segment; 465 goto segment;
459 } 466 }
460 467
461 /* TODO: for now, disable A-MSDU inside AMPDU */ 468 /*
462 if (info->flags & IEEE80211_TX_CTL_AMPDU) { 469 * No need to lock amsdu_in_ampdu_allowed since it can't be modified
470 * during an BA session.
471 */
472 if (info->flags & IEEE80211_TX_CTL_AMPDU &&
473 !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) {
463 num_subframes = 1; 474 num_subframes = 1;
464 pad = 0; 475 pad = 0;
465 goto segment; 476 goto segment;
466 } 477 }
467 478
479 max_amsdu_len = sta->max_amsdu_len;
480
481 /*
482 * Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not
483 * supported. This is a spec requirement (IEEE 802.11-2015
484 * section 8.7.3 NOTE 3).
485 */
486 if (info->flags & IEEE80211_TX_CTL_AMPDU &&
487 !sta->vht_cap.vht_supported)
488 max_amsdu_len = min_t(unsigned int, max_amsdu_len, 4095);
489
468 /* Sub frame header + SNAP + IP header + TCP header + MSS */ 490 /* Sub frame header + SNAP + IP header + TCP header + MSS */
469 subf_len = sizeof(struct ethhdr) + snap_ip_tcp + mss; 491 subf_len = sizeof(struct ethhdr) + snap_ip_tcp + mss;
470 pad = (4 - subf_len) & 0x3; 492 pad = (4 - subf_len) & 0x3;
@@ -473,12 +495,9 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
473 * If we have N subframes in the A-MSDU, then the A-MSDU's size is 495 * If we have N subframes in the A-MSDU, then the A-MSDU's size is
474 * N * subf_len + (N - 1) * pad. 496 * N * subf_len + (N - 1) * pad.
475 */ 497 */
476 num_subframes = (sta->max_amsdu_len + pad) / (subf_len + pad); 498 num_subframes = (max_amsdu_len + pad) / (subf_len + pad);
477 if (num_subframes > 1) { 499 if (num_subframes > 1)
478 u8 *qc = ieee80211_get_qos_ctl((void *)skb->data);
479
480 *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT; 500 *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
481 }
482 501
483 tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) - 502 tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
484 tcp_hdrlen(skb) + skb->data_len; 503 tcp_hdrlen(skb) + skb->data_len;
@@ -555,7 +574,7 @@ segment:
555 info->driver_data[0] = (void *)(uintptr_t)amsdu_add; 574 info->driver_data[0] = (void *)(uintptr_t)amsdu_add;
556 skb_shinfo(tmp)->gso_size = mss; 575 skb_shinfo(tmp)->gso_size = mss;
557 } else { 576 } else {
558 u8 *qc = ieee80211_get_qos_ctl((void *)tmp->data); 577 qc = ieee80211_get_qos_ctl((void *)tmp->data);
559 578
560 if (ipv4) 579 if (ipv4)
561 ip_send_check(ip_hdr(tmp)); 580 ip_send_check(ip_hdr(tmp));