diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-09-29 10:04:38 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-09-30 15:57:21 -0400 |
commit | 40b96408831f038b1a6b45e8b22cd050f82a3896 (patch) | |
tree | c8ea29b9d01ba28d484cf2d4c4a0cd576d598b79 /net/mac80211/sta_info.c | |
parent | 5bade101eceedb716e39bd35b2928c465e3fbd10 (diff) |
mac80211: explicitly notify drivers of frame release
iwlwifi needs to know the number of frames that are
going to be sent to a station while it is asleep so
it can properly handle the uCode blocking of that
station.
Before uAPSD, we got by by telling the device that
a single frame was going to be released whenever we
encountered IEEE80211_TX_CTL_POLL_RESPONSE. With
uAPSD, however, that is no longer possible since
there could be more than a single frame.
To support this model, add a new callback to notify
drivers when frames are going to be released.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 34 |
1 files changed, 25 insertions, 9 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a00358224cd5..907b42081f3c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -1169,7 +1169,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1169 | 1169 | ||
1170 | static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | 1170 | static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, |
1171 | struct sta_info *sta, int tid, | 1171 | struct sta_info *sta, int tid, |
1172 | bool uapsd) | 1172 | enum ieee80211_frame_release_type reason) |
1173 | { | 1173 | { |
1174 | struct ieee80211_local *local = sdata->local; | 1174 | struct ieee80211_local *local = sdata->local; |
1175 | struct ieee80211_qos_hdr *nullfunc; | 1175 | struct ieee80211_qos_hdr *nullfunc; |
@@ -1210,7 +1210,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
1210 | 1210 | ||
1211 | nullfunc->qos_ctrl = cpu_to_le16(tid); | 1211 | nullfunc->qos_ctrl = cpu_to_le16(tid); |
1212 | 1212 | ||
1213 | if (uapsd) | 1213 | if (reason == IEEE80211_FRAME_RELEASE_UAPSD) |
1214 | nullfunc->qos_ctrl |= | 1214 | nullfunc->qos_ctrl |= |
1215 | cpu_to_le16(IEEE80211_QOS_CTL_EOSP); | 1215 | cpu_to_le16(IEEE80211_QOS_CTL_EOSP); |
1216 | } | 1216 | } |
@@ -1227,6 +1227,8 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
1227 | IEEE80211_TX_STATUS_EOSP | | 1227 | IEEE80211_TX_STATUS_EOSP | |
1228 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 1228 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
1229 | 1229 | ||
1230 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false); | ||
1231 | |||
1230 | ieee80211_xmit(sdata, skb); | 1232 | ieee80211_xmit(sdata, skb); |
1231 | } | 1233 | } |
1232 | 1234 | ||
@@ -1324,20 +1326,24 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
1324 | /* This will evaluate to 1, 3, 5 or 7. */ | 1326 | /* This will evaluate to 1, 3, 5 or 7. */ |
1325 | tid = 7 - ((ffs(~ignored_acs) - 1) << 1); | 1327 | tid = 7 - ((ffs(~ignored_acs) - 1) << 1); |
1326 | 1328 | ||
1327 | ieee80211_send_null_response(sdata, sta, tid, | 1329 | ieee80211_send_null_response(sdata, sta, tid, reason); |
1328 | reason == IEEE80211_FRAME_RELEASE_UAPSD); | ||
1329 | return; | 1330 | return; |
1330 | } | 1331 | } |
1331 | 1332 | ||
1332 | if (!driver_release_tids) { | 1333 | if (!driver_release_tids) { |
1333 | struct sk_buff_head pending; | 1334 | struct sk_buff_head pending; |
1334 | struct sk_buff *skb; | 1335 | struct sk_buff *skb; |
1336 | int num = 0; | ||
1337 | u16 tids = 0; | ||
1335 | 1338 | ||
1336 | skb_queue_head_init(&pending); | 1339 | skb_queue_head_init(&pending); |
1337 | 1340 | ||
1338 | while ((skb = __skb_dequeue(&frames))) { | 1341 | while ((skb = __skb_dequeue(&frames))) { |
1339 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1342 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1340 | struct ieee80211_hdr *hdr = (void *) skb->data; | 1343 | struct ieee80211_hdr *hdr = (void *) skb->data; |
1344 | u8 *qoshdr = NULL; | ||
1345 | |||
1346 | num++; | ||
1341 | 1347 | ||
1342 | /* | 1348 | /* |
1343 | * Tell TX path to send this frame even though the | 1349 | * Tell TX path to send this frame even though the |
@@ -1357,19 +1363,29 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
1357 | hdr->frame_control |= | 1363 | hdr->frame_control |= |
1358 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 1364 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
1359 | 1365 | ||
1366 | if (ieee80211_is_data_qos(hdr->frame_control) || | ||
1367 | ieee80211_is_qos_nullfunc(hdr->frame_control)) | ||
1368 | qoshdr = ieee80211_get_qos_ctl(hdr); | ||
1369 | |||
1370 | /* set EOSP for the frame */ | ||
1360 | if (reason == IEEE80211_FRAME_RELEASE_UAPSD && | 1371 | if (reason == IEEE80211_FRAME_RELEASE_UAPSD && |
1361 | skb_queue_empty(&frames)) { | 1372 | qoshdr && skb_queue_empty(&frames)) |
1362 | /* set EOSP for the frame */ | 1373 | *qoshdr |= IEEE80211_QOS_CTL_EOSP; |
1363 | u8 *p = ieee80211_get_qos_ctl(hdr); | ||
1364 | *p |= IEEE80211_QOS_CTL_EOSP; | ||
1365 | } | ||
1366 | 1374 | ||
1367 | info->flags |= IEEE80211_TX_STATUS_EOSP | | 1375 | info->flags |= IEEE80211_TX_STATUS_EOSP | |
1368 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 1376 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
1369 | 1377 | ||
1378 | if (qoshdr) | ||
1379 | tids |= BIT(*qoshdr & IEEE80211_QOS_CTL_TID_MASK); | ||
1380 | else | ||
1381 | tids |= BIT(0); | ||
1382 | |||
1370 | __skb_queue_tail(&pending, skb); | 1383 | __skb_queue_tail(&pending, skb); |
1371 | } | 1384 | } |
1372 | 1385 | ||
1386 | drv_allow_buffered_frames(local, sta, tids, num, | ||
1387 | reason, more_data); | ||
1388 | |||
1373 | ieee80211_add_pending_skbs(local, &pending); | 1389 | ieee80211_add_pending_skbs(local, &pending); |
1374 | 1390 | ||
1375 | sta_info_recalc_tim(sta); | 1391 | sta_info_recalc_tim(sta); |