diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-09-29 16:04:38 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-09-30 15:57:21 -0400 |
commit | 40b96408831f038b1a6b45e8b22cd050f82a3896 (patch) | |
tree | c8ea29b9d01ba28d484cf2d4c4a0cd576d598b79 /net/mac80211 | |
parent | 5bade101eceedb716e39bd35b2928c465e3fbd10 (diff) | |
download | lwn-40b96408831f038b1a6b45e8b22cd050f82a3896.tar.gz lwn-40b96408831f038b1a6b45e8b22cd050f82a3896.zip |
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')
-rw-r--r-- | net/mac80211/driver-ops.h | 15 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 22 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 34 |
3 files changed, 61 insertions, 10 deletions
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 8fa0d2edf54c..68721d379fe1 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -685,4 +685,19 @@ drv_release_buffered_frames(struct ieee80211_local *local, more_data); trace_drv_return_void(local); } + +static inline void +drv_allow_buffered_frames(struct ieee80211_local *local, + struct sta_info *sta, u16 tids, int num_frames, + enum ieee80211_frame_release_type reason, + bool more_data) +{ + trace_drv_allow_buffered_frames(local, &sta->sta, tids, num_frames, + reason, more_data); + if (local->ops->allow_buffered_frames) + local->ops->allow_buffered_frames(&local->hw, &sta->sta, + tids, num_frames, reason, + more_data); + trace_drv_return_void(local); +} #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 531fbd086794..aef08969e353 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -1129,7 +1129,7 @@ TRACE_EVENT(drv_rssi_callback, ) ); -TRACE_EVENT(drv_release_buffered_frames, +DECLARE_EVENT_CLASS(release_evt, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sta *sta, u16 tids, int num_frames, @@ -1164,6 +1164,26 @@ TRACE_EVENT(drv_release_buffered_frames, ) ); +DEFINE_EVENT(release_evt, drv_release_buffered_frames, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sta *sta, + u16 tids, int num_frames, + enum ieee80211_frame_release_type reason, + bool more_data), + + TP_ARGS(local, sta, tids, num_frames, reason, more_data) +); + +DEFINE_EVENT(release_evt, drv_allow_buffered_frames, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sta *sta, + u16 tids, int num_frames, + enum ieee80211_frame_release_type reason, + bool more_data), + + TP_ARGS(local, sta, tids, num_frames, reason, more_data) +); + /* * Tracing for API calls that drivers call. */ 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) static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, int tid, - bool uapsd) + enum ieee80211_frame_release_type reason) { struct ieee80211_local *local = sdata->local; struct ieee80211_qos_hdr *nullfunc; @@ -1210,7 +1210,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, nullfunc->qos_ctrl = cpu_to_le16(tid); - if (uapsd) + if (reason == IEEE80211_FRAME_RELEASE_UAPSD) nullfunc->qos_ctrl |= cpu_to_le16(IEEE80211_QOS_CTL_EOSP); } @@ -1227,6 +1227,8 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, IEEE80211_TX_STATUS_EOSP | IEEE80211_TX_CTL_REQ_TX_STATUS; + drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false); + ieee80211_xmit(sdata, skb); } @@ -1324,20 +1326,24 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, /* This will evaluate to 1, 3, 5 or 7. */ tid = 7 - ((ffs(~ignored_acs) - 1) << 1); - ieee80211_send_null_response(sdata, sta, tid, - reason == IEEE80211_FRAME_RELEASE_UAPSD); + ieee80211_send_null_response(sdata, sta, tid, reason); return; } if (!driver_release_tids) { struct sk_buff_head pending; struct sk_buff *skb; + int num = 0; + u16 tids = 0; skb_queue_head_init(&pending); while ((skb = __skb_dequeue(&frames))) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (void *) skb->data; + u8 *qoshdr = NULL; + + num++; /* * Tell TX path to send this frame even though the @@ -1357,19 +1363,29 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); + if (ieee80211_is_data_qos(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control)) + qoshdr = ieee80211_get_qos_ctl(hdr); + + /* set EOSP for the frame */ if (reason == IEEE80211_FRAME_RELEASE_UAPSD && - skb_queue_empty(&frames)) { - /* set EOSP for the frame */ - u8 *p = ieee80211_get_qos_ctl(hdr); - *p |= IEEE80211_QOS_CTL_EOSP; - } + qoshdr && skb_queue_empty(&frames)) + *qoshdr |= IEEE80211_QOS_CTL_EOSP; info->flags |= IEEE80211_TX_STATUS_EOSP | IEEE80211_TX_CTL_REQ_TX_STATUS; + if (qoshdr) + tids |= BIT(*qoshdr & IEEE80211_QOS_CTL_TID_MASK); + else + tids |= BIT(0); + __skb_queue_tail(&pending, skb); } + drv_allow_buffered_frames(local, sta, tids, num, + reason, more_data); + ieee80211_add_pending_skbs(local, &pending); sta_info_recalc_tim(sta); |