summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorLiad Kaufman <liad.kaufman@intel.com>2014-11-19 06:47:38 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-11-19 12:45:36 -0500
commitb6da911b3cf1d342f2f7123c9eb6463d299bca4e (patch)
tree7e90aaf36e8149ca731e4d8589d9d18556de933b /net
parent4f9610d528a6aa5642fa350fa93fbd905a753ae8 (diff)
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>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/agg-tx.c7
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/sta_info.c3
-rw-r--r--net/mac80211/sta_info.h6
-rw-r--r--net/mac80211/tx.c91
-rw-r--r--net/mac80211/wme.c39
6 files changed, 147 insertions, 0 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 9242c60048cf..a360c15cc978 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -509,6 +509,10 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
509 struct tid_ampdu_tx *tid_tx; 509 struct tid_ampdu_tx *tid_tx;
510 int ret = 0; 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 trace_api_start_tx_ba_session(pubsta, tid); 516 trace_api_start_tx_ba_session(pubsta, tid);
513 517
514 if (WARN_ON_ONCE(!local->ops->ampdu_action)) 518 if (WARN_ON_ONCE(!local->ops->ampdu_action))
@@ -765,6 +769,9 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
765 goto unlock; 769 goto unlock;
766 } 770 }
767 771
772 WARN(sta->reserved_tid == tid,
773 "Requested to stop BA session on reserved tid=%d", tid);
774
768 if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { 775 if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
769 /* already in progress stopping it */ 776 /* already in progress stopping it */
770 ret = 0; 777 ret = 0;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a30d40839d49..34168c21bf06 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1011,6 +1011,7 @@ enum queue_stop_reason {
1011 IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, 1011 IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL,
1012 IEEE80211_QUEUE_STOP_REASON_FLUSH, 1012 IEEE80211_QUEUE_STOP_REASON_FLUSH,
1013 IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN, 1013 IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN,
1014 IEEE80211_QUEUE_STOP_REASON_RESERVE_TID,
1014 1015
1015 IEEE80211_QUEUE_STOP_REASONS, 1016 IEEE80211_QUEUE_STOP_REASONS,
1016}; 1017};
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 86ca62765699..a42f5b2b024d 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -351,6 +351,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
351 351
352 sta->sta_state = IEEE80211_STA_NONE; 352 sta->sta_state = IEEE80211_STA_NONE;
353 353
354 /* Mark TID as unreserved */
355 sta->reserved_tid = IEEE80211_TID_UNRESERVED;
356
354 ktime_get_ts(&uptime); 357 ktime_get_ts(&uptime);
355 sta->last_connected = uptime.tv_sec; 358 sta->last_connected = uptime.tv_sec;
356 ewma_init(&sta->avg_signal, 1024, 8); 359 ewma_init(&sta->avg_signal, 1024, 8);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 00f56eb72c60..4f052bb2a5ad 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -254,6 +254,9 @@ struct ieee80211_tx_latency_stat {
254 u32 bin_count; 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 * struct sta_info - STA information 261 * struct sta_info - STA information
259 * 262 *
@@ -342,6 +345,7 @@ struct ieee80211_tx_latency_stat {
342 * AP only. 345 * AP only.
343 * @cipher_scheme: optional cipher scheme for this station 346 * @cipher_scheme: optional cipher scheme for this station
344 * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed 347 * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed
348 * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED)
345 */ 349 */
346struct sta_info { 350struct sta_info {
347 /* General information, mostly static */ 351 /* General information, mostly static */
@@ -459,6 +463,8 @@ struct sta_info {
459 /* TDLS timeout data */ 463 /* TDLS timeout data */
460 unsigned long last_tdls_pkt_time; 464 unsigned long last_tdls_pkt_time;
461 465
466 u8 reserved_tid;
467
462 /* keep last! */ 468 /* keep last! */
463 struct ieee80211_sta sta; 469 struct ieee80211_sta sta;
464}; 470};
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 2dd89670e1cd..0cb41d1a1f20 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3107,6 +3107,97 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
3107} 3107}
3108EXPORT_SYMBOL(ieee80211_get_buffered_bc); 3108EXPORT_SYMBOL(ieee80211_get_buffered_bc);
3109 3109
3110int 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}
3172EXPORT_SYMBOL(ieee80211_reserve_tid);
3173
3174void 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}
3199EXPORT_SYMBOL(ieee80211_unreserve_tid);
3200
3110void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, 3201void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
3111 struct sk_buff *skb, int tid, 3202 struct sk_buff *skb, int tid,
3112 enum ieee80211_band band) 3203 enum ieee80211_band band)
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index fdf52db95b33..9eb0aee9105b 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -53,6 +53,36 @@ static int wme_downgrade_ac(struct sk_buff *skb)
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 */
62static 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
56static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, 86static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata,
57 struct sta_info *sta, struct sk_buff *skb) 87 struct sta_info *sta, struct sk_buff *skb)
58{ 88{
@@ -77,6 +107,10 @@ static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata,
77 } 107 }
78 } 108 }
79 109
110 /* Check to see if this is a reserved TID */
111 if (sta && sta->reserved_tid == skb->priority)
112 skb->priority = ieee80211_fix_reserved_tid(skb->priority);
113
80 /* look up which queue to use for frames with this 1d tag */ 114 /* look up which queue to use for frames with this 1d tag */
81 return ieee802_1d_to_ac[skb->priority]; 115 return ieee802_1d_to_ac[skb->priority];
82} 116}
@@ -143,6 +177,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
143 break; 177 break;
144#endif 178#endif
145 case NL80211_IFTYPE_STATION: 179 case NL80211_IFTYPE_STATION:
180 /* might be a TDLS station */
181 sta = sta_info_get(sdata, skb->data);
182 if (sta)
183 qos = sta->sta.wme;
184
146 ra = sdata->u.mgd.bssid; 185 ra = sdata->u.mgd.bssid;
147 break; 186 break;
148 case NL80211_IFTYPE_ADHOC: 187 case NL80211_IFTYPE_ADHOC: