Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 266522
b: refs/heads/master
c: 4049e09
h: refs/heads/master
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed Sep 30, 2011
1 parent 3c91176 commit e2ffaea
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 17 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8a8656fa5bbbc8568348d95184d374edb03a48b7
refs/heads/master: 4049e09acdf4ffd270cb8fbf1cf5b39c3d02357c
31 changes: 31 additions & 0 deletions trunk/include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,14 @@ enum ieee80211_tx_sync_type {
IEEE80211_TX_SYNC_ACTION,
};

/**
* enum ieee80211_frame_release_type - frame release reason
* @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll
*/
enum ieee80211_frame_release_type {
IEEE80211_FRAME_RELEASE_PSPOLL,
};

/**
* struct ieee80211_ops - callbacks from mac80211 to the driver
*
Expand Down Expand Up @@ -1931,6 +1939,23 @@ enum ieee80211_tx_sync_type {
* The callback can sleep.
* @rssi_callback: Notify driver when the average RSSI goes above/below
* thresholds that were registered previously. The callback can sleep.
*
* @release_buffered_frames: Release buffered frames according to the given
* parameters. In the case where the driver buffers some frames for
* sleeping stations mac80211 will use this callback to tell the driver
* to release some frames, either for PS-poll or uAPSD.
* Note that if the @more_data paramter is %false the driver must check
* if there are more frames on the given TIDs, and if there are more than
* the frames being released then it must still set the more-data bit in
* the frame. If the @more_data parameter is %true, then of course the
* more-data bit must always be set.
* The @tids parameter tells the driver which TIDs to release frames
* from, for PS-poll it will always have only a single bit set.
* In the case this is used for uAPSD, the @num_frames parameter may be
* bigger than one, but the driver may send fewer frames (it must send
* at least one, however). In this case it is also responsible for
* setting the EOSP flag in the QoS header of the frames.
* This callback must be atomic.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
Expand Down Expand Up @@ -2045,6 +2070,12 @@ struct ieee80211_ops {
const struct cfg80211_bitrate_mask *mask);
void (*rssi_callback)(struct ieee80211_hw *hw,
enum ieee80211_rssi_event rssi_event);

void (*release_buffered_frames)(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tids, int num_frames,
enum ieee80211_frame_release_type reason,
bool more_data);
};

/**
Expand Down
15 changes: 15 additions & 0 deletions trunk/net/mac80211/driver-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -670,4 +670,19 @@ static inline void drv_rssi_callback(struct ieee80211_local *local,
local->ops->rssi_callback(&local->hw, event);
trace_drv_return_void(local);
}

static inline void
drv_release_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_release_buffered_frames(local, &sta->sta, tids, num_frames,
reason, more_data);
if (local->ops->release_buffered_frames)
local->ops->release_buffered_frames(&local->hw, &sta->sta, tids,
num_frames, reason,
more_data);
trace_drv_return_void(local);
}
#endif /* __MAC80211_DRIVER_OPS */
35 changes: 35 additions & 0 deletions trunk/net/mac80211/driver-trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,41 @@ TRACE_EVENT(drv_rssi_callback,
)
);

TRACE_EVENT(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),

TP_STRUCT__entry(
LOCAL_ENTRY
STA_ENTRY
__field(u16, tids)
__field(int, num_frames)
__field(int, reason)
__field(bool, more_data)
),

TP_fast_assign(
LOCAL_ASSIGN;
STA_ASSIGN;
__entry->tids = tids;
__entry->num_frames = num_frames;
__entry->reason = reason;
__entry->more_data = more_data;
),

TP_printk(
LOCAL_PR_FMT STA_PR_FMT
" TIDs:0x%.4x frames:%d reason:%d more:%d",
LOCAL_PR_ARG, STA_PR_ARG, __entry->tids, __entry->num_frames,
__entry->reason, __entry->more_data
)
);

/*
* Tracing for API calls that drivers call.
*/
Expand Down
82 changes: 66 additions & 16 deletions trunk/net/mac80211/sta_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -1157,8 +1157,10 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb = NULL;
bool found = false;
bool more_data = false;
int ac;
unsigned long driver_release_tids = 0;
u8 ignore_for_response = sta->sta.uapsd_queues;

/*
Expand All @@ -1173,19 +1175,40 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
* Get response frame and more data bit for it.
*/
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
unsigned long tids;

if (ignore_for_response & BIT(ac))
continue;

if (!skb) {
skb = skb_dequeue(&sta->tx_filtered[ac]);
if (!skb) {
skb = skb_dequeue(&sta->ps_tx_buf[ac]);
tids = ieee80211_tids_for_ac(ac);

if (!found) {
driver_release_tids = sta->driver_buffered_tids & tids;
if (driver_release_tids) {
found = true;
} else {
skb = skb_dequeue(&sta->tx_filtered[ac]);
if (!skb) {
skb = skb_dequeue(&sta->ps_tx_buf[ac]);
if (skb)
local->total_ps_buffered--;
}
if (skb)
local->total_ps_buffered--;
found = true;
}
}

/* FIXME: take into account driver-buffered frames */
/*
* If the driver has data on more than one TID then
* certainly there's more data if we release just a
* single frame now (from a single TID).
*/
if (hweight16(driver_release_tids) > 1) {
more_data = true;
driver_release_tids =
BIT(ffs(driver_release_tids) - 1);
break;
}
}

if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
!skb_queue_empty(&sta->ps_tx_buf[ac])) {
Expand All @@ -1194,6 +1217,22 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
}
}

if (!found) {
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
/*
* FIXME: This can be the result of a race condition between
* us expiring a frame and the station polling for it.
* Should we send it a null-func frame indicating we
* have nothing buffered for it?
*/
printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
"though there are no buffered frames for it\n",
sdata->name, sta->sta.addr);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */

return;
}

if (skb) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr =
Expand All @@ -1220,18 +1259,29 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
ieee80211_add_pending_skb(local, skb);

sta_info_recalc_tim(sta);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
} else {
/*
* FIXME: This can be the result of a race condition between
* us expiring a frame and the station polling for it.
* Should we send it a null-func frame indicating we
* have nothing buffered for it?
* We need to release a frame that is buffered somewhere in the
* driver ... it'll have to handle that.
* Note that, as per the comment above, it'll also have to see
* if there is more than just one frame on the specific TID that
* we're releasing from, and it needs to set the more-data bit
* accordingly if we tell it that there's no more data. If we do
* tell it there's more data, then of course the more-data bit
* needs to be set anyway.
*/
drv_release_buffered_frames(local, sta, driver_release_tids,
1, IEEE80211_FRAME_RELEASE_PSPOLL,
more_data);

/*
* Note that we don't recalculate the TIM bit here as it would
* most likely have no effect at all unless the driver told us
* that the TID became empty before returning here from the
* release function.
* Either way, however, when the driver tells us that the TID
* became empty we'll do the TIM recalculation.
*/
printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
"though there are no buffered frames for it\n",
sdata->name, sta->sta.addr);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
}
}

Expand Down

0 comments on commit e2ffaea

Please sign in to comment.