Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: synchronously reserve TID per station

In TDLS (e.g., TDLS off-channel) there is a requirement for
some drivers to supply an unused TID between the AP and the
device to the FW, to allow sending PTI requests and to allow
the FW to aggregate on a specific TID for better throughput.

To ensure that the allocated TID is indeed unused, this patch
introduces an API for blocking the driver from TXing on that
TID.

Signed-off-by: Liad Kaufman <liad.kaufman@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Liad Kaufman and committed by
Johannes Berg
b6da911b 4f9610d5

+184
+37
include/net/mac80211.h
··· 5071 5071 u16 reason_code, gfp_t gfp); 5072 5072 5073 5073 /** 5074 + * ieee80211_reserve_tid - request to reserve a specific TID 5075 + * 5076 + * There is sometimes a need (such as in TDLS) for blocking the driver from 5077 + * using a specific TID so that the FW can use it for certain operations such 5078 + * as sending PTI requests. To make sure that the driver doesn't use that TID, 5079 + * this function must be called as it flushes out packets on this TID and marks 5080 + * it as blocked, so that any transmit for the station on this TID will be 5081 + * redirected to the alternative TID in the same AC. 5082 + * 5083 + * Note that this function blocks and may call back into the driver, so it 5084 + * should be called without driver locks held. Also note this function should 5085 + * only be called from the driver's @sta_state callback. 5086 + * 5087 + * @sta: the station to reserve the TID for 5088 + * @tid: the TID to reserve 5089 + * 5090 + * Returns: 0 on success, else on failure 5091 + */ 5092 + int ieee80211_reserve_tid(struct ieee80211_sta *sta, u8 tid); 5093 + 5094 + /** 5095 + * ieee80211_unreserve_tid - request to unreserve a specific TID 5096 + * 5097 + * Once there is no longer any need for reserving a certain TID, this function 5098 + * should be called, and no longer will packets have their TID modified for 5099 + * preventing use of this TID in the driver. 5100 + * 5101 + * Note that this function blocks and acquires a lock, so it should be called 5102 + * without driver locks held. Also note this function should only be called 5103 + * from the driver's @sta_state callback. 5104 + * 5105 + * @sta: the station 5106 + * @tid: the TID to unreserve 5107 + */ 5108 + void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid); 5109 + 5110 + /** 5074 5111 * ieee80211_ie_split - split an IE buffer according to ordering 5075 5112 * 5076 5113 * @ies: the IE buffer
+7
net/mac80211/agg-tx.c
··· 509 509 struct tid_ampdu_tx *tid_tx; 510 510 int ret = 0; 511 511 512 + if (WARN(sta->reserved_tid == tid, 513 + "Requested to start BA session on reserved tid=%d", tid)) 514 + return -EINVAL; 515 + 512 516 trace_api_start_tx_ba_session(pubsta, tid); 513 517 514 518 if (WARN_ON_ONCE(!local->ops->ampdu_action)) ··· 768 764 ret = -ENOENT; 769 765 goto unlock; 770 766 } 767 + 768 + WARN(sta->reserved_tid == tid, 769 + "Requested to stop BA session on reserved tid=%d", tid); 771 770 772 771 if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { 773 772 /* already in progress stopping it */
+1
net/mac80211/ieee80211_i.h
··· 1011 1011 IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, 1012 1012 IEEE80211_QUEUE_STOP_REASON_FLUSH, 1013 1013 IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN, 1014 + IEEE80211_QUEUE_STOP_REASON_RESERVE_TID, 1014 1015 1015 1016 IEEE80211_QUEUE_STOP_REASONS, 1016 1017 };
+3
net/mac80211/sta_info.c
··· 351 351 352 352 sta->sta_state = IEEE80211_STA_NONE; 353 353 354 + /* Mark TID as unreserved */ 355 + sta->reserved_tid = IEEE80211_TID_UNRESERVED; 356 + 354 357 ktime_get_ts(&uptime); 355 358 sta->last_connected = uptime.tv_sec; 356 359 ewma_init(&sta->avg_signal, 1024, 8);
+6
net/mac80211/sta_info.h
··· 254 254 u32 bin_count; 255 255 }; 256 256 257 + /* Value to indicate no TID reservation */ 258 + #define IEEE80211_TID_UNRESERVED 0xff 259 + 257 260 /** 258 261 * struct sta_info - STA information 259 262 * ··· 345 342 * AP only. 346 343 * @cipher_scheme: optional cipher scheme for this station 347 344 * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed 345 + * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) 348 346 */ 349 347 struct sta_info { 350 348 /* General information, mostly static */ ··· 462 458 463 459 /* TDLS timeout data */ 464 460 unsigned long last_tdls_pkt_time; 461 + 462 + u8 reserved_tid; 465 463 466 464 /* keep last! */ 467 465 struct ieee80211_sta sta;
+91
net/mac80211/tx.c
··· 3107 3107 } 3108 3108 EXPORT_SYMBOL(ieee80211_get_buffered_bc); 3109 3109 3110 + int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid) 3111 + { 3112 + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 3113 + struct ieee80211_sub_if_data *sdata = sta->sdata; 3114 + struct ieee80211_local *local = sdata->local; 3115 + int ret; 3116 + u32 queues; 3117 + 3118 + lockdep_assert_held(&local->sta_mtx); 3119 + 3120 + /* only some cases are supported right now */ 3121 + switch (sdata->vif.type) { 3122 + case NL80211_IFTYPE_STATION: 3123 + case NL80211_IFTYPE_AP: 3124 + case NL80211_IFTYPE_AP_VLAN: 3125 + break; 3126 + default: 3127 + WARN_ON(1); 3128 + return -EINVAL; 3129 + } 3130 + 3131 + if (WARN_ON(tid >= IEEE80211_NUM_UPS)) 3132 + return -EINVAL; 3133 + 3134 + if (sta->reserved_tid == tid) { 3135 + ret = 0; 3136 + goto out; 3137 + } 3138 + 3139 + if (sta->reserved_tid != IEEE80211_TID_UNRESERVED) { 3140 + sdata_err(sdata, "TID reservation already active\n"); 3141 + ret = -EALREADY; 3142 + goto out; 3143 + } 3144 + 3145 + ieee80211_stop_vif_queues(sdata->local, sdata, 3146 + IEEE80211_QUEUE_STOP_REASON_RESERVE_TID); 3147 + 3148 + synchronize_net(); 3149 + 3150 + /* Tear down BA sessions so we stop aggregating on this TID */ 3151 + if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) { 3152 + set_sta_flag(sta, WLAN_STA_BLOCK_BA); 3153 + __ieee80211_stop_tx_ba_session(sta, tid, 3154 + AGG_STOP_LOCAL_REQUEST); 3155 + } 3156 + 3157 + queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]); 3158 + __ieee80211_flush_queues(local, sdata, queues); 3159 + 3160 + sta->reserved_tid = tid; 3161 + 3162 + ieee80211_wake_vif_queues(local, sdata, 3163 + IEEE80211_QUEUE_STOP_REASON_RESERVE_TID); 3164 + 3165 + if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) 3166 + clear_sta_flag(sta, WLAN_STA_BLOCK_BA); 3167 + 3168 + ret = 0; 3169 + out: 3170 + return ret; 3171 + } 3172 + EXPORT_SYMBOL(ieee80211_reserve_tid); 3173 + 3174 + void ieee80211_unreserve_tid(struct ieee80211_sta *pubsta, u8 tid) 3175 + { 3176 + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 3177 + struct ieee80211_sub_if_data *sdata = sta->sdata; 3178 + 3179 + lockdep_assert_held(&sdata->local->sta_mtx); 3180 + 3181 + /* only some cases are supported right now */ 3182 + switch (sdata->vif.type) { 3183 + case NL80211_IFTYPE_STATION: 3184 + case NL80211_IFTYPE_AP: 3185 + case NL80211_IFTYPE_AP_VLAN: 3186 + break; 3187 + default: 3188 + WARN_ON(1); 3189 + return; 3190 + } 3191 + 3192 + if (tid != sta->reserved_tid) { 3193 + sdata_err(sdata, "TID to unreserve (%d) isn't reserved\n", tid); 3194 + return; 3195 + } 3196 + 3197 + sta->reserved_tid = IEEE80211_TID_UNRESERVED; 3198 + } 3199 + EXPORT_SYMBOL(ieee80211_unreserve_tid); 3200 + 3110 3201 void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, 3111 3202 struct sk_buff *skb, int tid, 3112 3203 enum ieee80211_band band)
+39
net/mac80211/wme.c
··· 53 53 } 54 54 } 55 55 56 + /** 57 + * ieee80211_fix_reserved_tid - return the TID to use if this one is reserved 58 + * @tid: the assumed-reserved TID 59 + * 60 + * Returns: the alternative TID to use, or 0 on error 61 + */ 62 + static inline u8 ieee80211_fix_reserved_tid(u8 tid) 63 + { 64 + switch (tid) { 65 + case 0: 66 + return 3; 67 + case 1: 68 + return 2; 69 + case 2: 70 + return 1; 71 + case 3: 72 + return 0; 73 + case 4: 74 + return 5; 75 + case 5: 76 + return 4; 77 + case 6: 78 + return 7; 79 + case 7: 80 + return 6; 81 + } 82 + 83 + return 0; 84 + } 85 + 56 86 static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, 57 87 struct sta_info *sta, struct sk_buff *skb) 58 88 { ··· 106 76 break; 107 77 } 108 78 } 79 + 80 + /* Check to see if this is a reserved TID */ 81 + if (sta && sta->reserved_tid == skb->priority) 82 + skb->priority = ieee80211_fix_reserved_tid(skb->priority); 109 83 110 84 /* look up which queue to use for frames with this 1d tag */ 111 85 return ieee802_1d_to_ac[skb->priority]; ··· 177 143 break; 178 144 #endif 179 145 case NL80211_IFTYPE_STATION: 146 + /* might be a TDLS station */ 147 + sta = sta_info_get(sdata, skb->data); 148 + if (sta) 149 + qos = sta->sta.wme; 150 + 180 151 ra = sdata->u.mgd.bssid; 181 152 break; 182 153 case NL80211_IFTYPE_ADHOC: