aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2016-03-03 16:59:00 -0500
committerJohannes Berg <johannes.berg@intel.com>2016-04-06 07:18:19 -0400
commit6e0456b5454561c4e9fa9e8a4acea405e6d56c80 (patch)
tree0d3203eaa74cb6ad1595040fe3373c90af84b5f0
parentc9c5962b56c10c34d8fedc20cd6d6ebdaa2383c6 (diff)
mac80211: add A-MSDU tx support
Requires software tx queueing and fast-xmit support. For good performance, drivers need frag_list support as well. This avoids the need for copying data of aggregated frames. Running without it is only supported for debugging purposes. To avoid performance and packet size issues, the rate control module or driver needs to limit the maximum A-MSDU size by setting max_rc_amsdu_len in struct ieee80211_sta. Signed-off-by: Felix Fietkau <nbd@openwrt.org> [fix locking issue] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/linux/ieee80211.h3
-rw-r--r--include/net/mac80211.h19
-rw-r--r--net/mac80211/agg-tx.c5
-rw-r--r--net/mac80211/debugfs.c2
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/sta_info.c2
-rw-r--r--net/mac80211/tx.c156
7 files changed, 188 insertions, 0 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 113bfc468a4d..b118744d3382 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -164,6 +164,9 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
164/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */ 164/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
165#define IEEE80211_MAX_FRAME_LEN 2352 165#define IEEE80211_MAX_FRAME_LEN 2352
166 166
167/* Maximal size of an A-MSDU that can be transported in a HT BA session */
168#define IEEE80211_MAX_MPDU_LEN_HT_BA 4095
169
167/* Maximal size of an A-MSDU */ 170/* Maximal size of an A-MSDU */
168#define IEEE80211_MAX_MPDU_LEN_HT_3839 3839 171#define IEEE80211_MAX_MPDU_LEN_HT_3839 3839
169#define IEEE80211_MAX_MPDU_LEN_HT_7935 7935 172#define IEEE80211_MAX_MPDU_LEN_HT_7935 7935
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 5f4b4c773a92..a3ee76559791 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -713,6 +713,7 @@ enum mac80211_tx_info_flags {
713 * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll 713 * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
714 * frame (PS-Poll or uAPSD). 714 * frame (PS-Poll or uAPSD).
715 * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information 715 * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
716 * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
716 * 717 *
717 * These flags are used in tx_info->control.flags. 718 * These flags are used in tx_info->control.flags.
718 */ 719 */
@@ -720,6 +721,7 @@ enum mac80211_tx_control_flags {
720 IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0), 721 IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
721 IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1), 722 IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
722 IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), 723 IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
724 IEEE80211_TX_CTRL_AMSDU = BIT(3),
723}; 725};
724 726
725/* 727/*
@@ -1746,6 +1748,7 @@ struct ieee80211_sta_rates {
1746 * Both additional HT limits must be enforced by the low level driver. 1748 * Both additional HT limits must be enforced by the low level driver.
1747 * This is defined by the spec (IEEE 802.11-2012 section 8.3.2.2 NOTE 2). 1749 * This is defined by the spec (IEEE 802.11-2012 section 8.3.2.2 NOTE 2).
1748 * @support_p2p_ps: indicates whether the STA supports P2P PS mechanism or not. 1750 * @support_p2p_ps: indicates whether the STA supports P2P PS mechanism or not.
1751 * @max_rc_amsdu_len: Maximum A-MSDU size in bytes recommended by rate control.
1749 * @txq: per-TID data TX queues (if driver uses the TXQ abstraction) 1752 * @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
1750 */ 1753 */
1751struct ieee80211_sta { 1754struct ieee80211_sta {
@@ -1767,6 +1770,7 @@ struct ieee80211_sta {
1767 u8 max_amsdu_subframes; 1770 u8 max_amsdu_subframes;
1768 u16 max_amsdu_len; 1771 u16 max_amsdu_len;
1769 bool support_p2p_ps; 1772 bool support_p2p_ps;
1773 u16 max_rc_amsdu_len;
1770 1774
1771 struct ieee80211_txq *txq[IEEE80211_NUM_TIDS]; 1775 struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
1772 1776
@@ -1983,6 +1987,15 @@ struct ieee80211_txq {
1983 * @IEEE80211_HW_USES_RSS: The device uses RSS and thus requires parallel RX, 1987 * @IEEE80211_HW_USES_RSS: The device uses RSS and thus requires parallel RX,
1984 * which implies using per-CPU station statistics. 1988 * which implies using per-CPU station statistics.
1985 * 1989 *
1990 * @IEEE80211_HW_TX_AMSDU: Hardware (or driver) supports software aggregated
1991 * A-MSDU frames. Requires software tx queueing and fast-xmit support.
1992 * When not using minstrel/minstrel_ht rate control, the driver must
1993 * limit the maximum A-MSDU size based on the current tx rate by setting
1994 * max_rc_amsdu_len in struct ieee80211_sta.
1995 *
1996 * @IEEE80211_HW_TX_FRAG_LIST: Hardware (or driver) supports sending frag_list
1997 * skbs, needed for zero-copy software A-MSDU.
1998 *
1986 * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays 1999 * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
1987 */ 2000 */
1988enum ieee80211_hw_flags { 2001enum ieee80211_hw_flags {
@@ -2021,6 +2034,8 @@ enum ieee80211_hw_flags {
2021 IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR, 2034 IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
2022 IEEE80211_HW_SUPPORTS_REORDERING_BUFFER, 2035 IEEE80211_HW_SUPPORTS_REORDERING_BUFFER,
2023 IEEE80211_HW_USES_RSS, 2036 IEEE80211_HW_USES_RSS,
2037 IEEE80211_HW_TX_AMSDU,
2038 IEEE80211_HW_TX_FRAG_LIST,
2024 2039
2025 /* keep last, obviously */ 2040 /* keep last, obviously */
2026 NUM_IEEE80211_HW_FLAGS 2041 NUM_IEEE80211_HW_FLAGS
@@ -2093,6 +2108,9 @@ enum ieee80211_hw_flags {
2093 * size is smaller (an example is LinkSys WRT120N with FW v1.0.07 2108 * size is smaller (an example is LinkSys WRT120N with FW v1.0.07
2094 * build 002 Jun 18 2012). 2109 * build 002 Jun 18 2012).
2095 * 2110 *
2111 * @max_tx_fragments: maximum number of tx buffers per (A)-MSDU, sum
2112 * of 1 + skb_shinfo(skb)->nr_frags for each skb in the frag_list.
2113 *
2096 * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX 2114 * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX
2097 * (if %IEEE80211_HW_QUEUE_CONTROL is set) 2115 * (if %IEEE80211_HW_QUEUE_CONTROL is set)
2098 * 2116 *
@@ -2147,6 +2165,7 @@ struct ieee80211_hw {
2147 u8 max_rate_tries; 2165 u8 max_rate_tries;
2148 u8 max_rx_aggregation_subframes; 2166 u8 max_rx_aggregation_subframes;
2149 u8 max_tx_aggregation_subframes; 2167 u8 max_tx_aggregation_subframes;
2168 u8 max_tx_fragments;
2150 u8 offchannel_tx_hw_queue; 2169 u8 offchannel_tx_hw_queue;
2151 u8 radiotap_mcs_details; 2170 u8 radiotap_mcs_details;
2152 u16 radiotap_vht_details; 2171 u16 radiotap_vht_details;
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 4932e9f243a2..42fa81031dfa 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -935,6 +935,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
935 size_t len) 935 size_t len)
936{ 936{
937 struct tid_ampdu_tx *tid_tx; 937 struct tid_ampdu_tx *tid_tx;
938 struct ieee80211_txq *txq;
938 u16 capab, tid; 939 u16 capab, tid;
939 u8 buf_size; 940 u8 buf_size;
940 bool amsdu; 941 bool amsdu;
@@ -945,6 +946,10 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
945 buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; 946 buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
946 buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes); 947 buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
947 948
949 txq = sta->sta.txq[tid];
950 if (!amsdu && txq)
951 set_bit(IEEE80211_TXQ_NO_AMSDU, &to_txq_info(txq)->flags);
952
948 mutex_lock(&sta->ampdu_mlme.mtx); 953 mutex_lock(&sta->ampdu_mlme.mtx);
949 954
950 tid_tx = rcu_dereference_protected_tid_tx(sta, tid); 955 tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 52ed2afc408d..b251b2f7f8dd 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -128,6 +128,8 @@ static const char *hw_flag_names[] = {
128 FLAG(NEEDS_UNIQUE_STA_ADDR), 128 FLAG(NEEDS_UNIQUE_STA_ADDR),
129 FLAG(SUPPORTS_REORDERING_BUFFER), 129 FLAG(SUPPORTS_REORDERING_BUFFER),
130 FLAG(USES_RSS), 130 FLAG(USES_RSS),
131 FLAG(TX_AMSDU),
132 FLAG(TX_FRAG_LIST),
131#undef FLAG 133#undef FLAG
132}; 134};
133 135
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6243109979ed..40c1d343992c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -802,6 +802,7 @@ struct mac80211_qos_map {
802enum txq_info_flags { 802enum txq_info_flags {
803 IEEE80211_TXQ_STOP, 803 IEEE80211_TXQ_STOP,
804 IEEE80211_TXQ_AMPDU, 804 IEEE80211_TXQ_AMPDU,
805 IEEE80211_TXQ_NO_AMSDU,
805}; 806};
806 807
807struct txq_info { 808struct txq_info {
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index cf2aca0cc200..960e13d8ed30 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -416,6 +416,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
416 } 416 }
417 } 417 }
418 418
419 sta->sta.max_rc_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_BA;
420
419 sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); 421 sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
420 422
421 return sta; 423 return sta;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 597c8fe672a3..4fa2842ddb25 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1324,6 +1324,10 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
1324out: 1324out:
1325 spin_unlock_bh(&txqi->queue.lock); 1325 spin_unlock_bh(&txqi->queue.lock);
1326 1326
1327 if (skb && skb_has_frag_list(skb) &&
1328 !ieee80211_hw_check(&local->hw, TX_FRAG_LIST))
1329 skb_linearize(skb);
1330
1327 return skb; 1331 return skb;
1328} 1332}
1329EXPORT_SYMBOL(ieee80211_tx_dequeue); 1333EXPORT_SYMBOL(ieee80211_tx_dequeue);
@@ -2802,6 +2806,154 @@ void ieee80211_clear_fast_xmit(struct sta_info *sta)
2802 kfree_rcu(fast_tx, rcu_head); 2806 kfree_rcu(fast_tx, rcu_head);
2803} 2807}
2804 2808
2809static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local,
2810 struct sk_buff *skb, int headroom,
2811 int *subframe_len)
2812{
2813 int amsdu_len = *subframe_len + sizeof(struct ethhdr);
2814 int padding = (4 - amsdu_len) & 3;
2815
2816 if (skb_headroom(skb) < headroom || skb_tailroom(skb) < padding) {
2817 I802_DEBUG_INC(local->tx_expand_skb_head);
2818
2819 if (pskb_expand_head(skb, headroom, padding, GFP_ATOMIC)) {
2820 wiphy_debug(local->hw.wiphy,
2821 "failed to reallocate TX buffer\n");
2822 return false;
2823 }
2824 }
2825
2826 if (padding) {
2827 *subframe_len += padding;
2828 memset(skb_put(skb, padding), 0, padding);
2829 }
2830
2831 return true;
2832}
2833
2834static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata,
2835 struct ieee80211_fast_tx *fast_tx,
2836 struct sk_buff *skb)
2837{
2838 struct ieee80211_local *local = sdata->local;
2839 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
2840 struct ieee80211_hdr *hdr;
2841 struct ethhdr amsdu_hdr;
2842 int hdr_len = fast_tx->hdr_len - sizeof(rfc1042_header);
2843 int subframe_len = skb->len - hdr_len;
2844 void *data;
2845 u8 *qc;
2846
2847 if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
2848 return false;
2849
2850 if (info->control.flags & IEEE80211_TX_CTRL_AMSDU)
2851 return true;
2852
2853 if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(amsdu_hdr),
2854 &subframe_len))
2855 return false;
2856
2857 amsdu_hdr.h_proto = cpu_to_be16(subframe_len);
2858 memcpy(amsdu_hdr.h_source, skb->data + fast_tx->sa_offs, ETH_ALEN);
2859 memcpy(amsdu_hdr.h_dest, skb->data + fast_tx->da_offs, ETH_ALEN);
2860
2861 data = skb_push(skb, sizeof(amsdu_hdr));
2862 memmove(data, data + sizeof(amsdu_hdr), hdr_len);
2863 memcpy(data + hdr_len, &amsdu_hdr, sizeof(amsdu_hdr));
2864
2865 hdr = data;
2866 qc = ieee80211_get_qos_ctl(hdr);
2867 *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
2868
2869 info->control.flags |= IEEE80211_TX_CTRL_AMSDU;
2870
2871 return true;
2872}
2873
2874static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
2875 struct sta_info *sta,
2876 struct ieee80211_fast_tx *fast_tx,
2877 struct sk_buff *skb)
2878{
2879 struct ieee80211_local *local = sdata->local;
2880 u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
2881 struct ieee80211_txq *txq = sta->sta.txq[tid];
2882 struct txq_info *txqi;
2883 struct sk_buff **frag_tail, *head;
2884 int subframe_len = skb->len - ETH_ALEN;
2885 u8 max_subframes = sta->sta.max_amsdu_subframes;
2886 int max_frags = local->hw.max_tx_fragments;
2887 int max_amsdu_len = sta->sta.max_amsdu_len;
2888 __be16 len;
2889 void *data;
2890 bool ret = false;
2891 int n = 1, nfrags;
2892
2893 if (!ieee80211_hw_check(&local->hw, TX_AMSDU))
2894 return false;
2895
2896 if (!txq)
2897 return false;
2898
2899 txqi = to_txq_info(txq);
2900 if (test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags))
2901 return false;
2902
2903 if (sta->sta.max_rc_amsdu_len)
2904 max_amsdu_len = min_t(int, max_amsdu_len,
2905 sta->sta.max_rc_amsdu_len);
2906
2907 spin_lock_bh(&txqi->queue.lock);
2908
2909 head = skb_peek_tail(&txqi->queue);
2910 if (!head)
2911 goto out;
2912
2913 if (skb->len + head->len > max_amsdu_len)
2914 goto out;
2915
2916 if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head))
2917 goto out;
2918
2919 nfrags = 1 + skb_shinfo(skb)->nr_frags;
2920 nfrags += 1 + skb_shinfo(head)->nr_frags;
2921 frag_tail = &skb_shinfo(head)->frag_list;
2922 while (*frag_tail) {
2923 nfrags += 1 + skb_shinfo(*frag_tail)->nr_frags;
2924 frag_tail = &(*frag_tail)->next;
2925 n++;
2926 }
2927
2928 if (max_subframes && n > max_subframes)
2929 goto out;
2930
2931 if (max_frags && nfrags > max_frags)
2932 goto out;
2933
2934 if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + 2,
2935 &subframe_len))
2936 goto out;
2937
2938 ret = true;
2939 data = skb_push(skb, ETH_ALEN + 2);
2940 memmove(data, data + ETH_ALEN + 2, 2 * ETH_ALEN);
2941
2942 data += 2 * ETH_ALEN;
2943 len = cpu_to_be16(subframe_len);
2944 memcpy(data, &len, 2);
2945 memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header));
2946
2947 head->len += skb->len;
2948 head->data_len += skb->len;
2949 *frag_tail = skb;
2950
2951out:
2952 spin_unlock_bh(&txqi->queue.lock);
2953
2954 return ret;
2955}
2956
2805static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, 2957static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
2806 struct net_device *dev, struct sta_info *sta, 2958 struct net_device *dev, struct sta_info *sta,
2807 struct ieee80211_fast_tx *fast_tx, 2959 struct ieee80211_fast_tx *fast_tx,
@@ -2856,6 +3008,10 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
2856 3008
2857 ieee80211_tx_stats(dev, skb->len + extra_head); 3009 ieee80211_tx_stats(dev, skb->len + extra_head);
2858 3010
3011 if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
3012 ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
3013 return true;
3014
2859 /* will not be crypto-handled beyond what we do here, so use false 3015 /* will not be crypto-handled beyond what we do here, so use false
2860 * as the may-encrypt argument for the resize to not account for 3016 * as the may-encrypt argument for the resize to not account for
2861 * more room than we already have in 'extra_head' 3017 * more room than we already have in 'extra_head'