Skip to content

Commit

Permalink
mac80211: Check for queued frames before entering power save.
Browse files Browse the repository at this point in the history
In a highly noisy environment, the tx rate of the driver drops and
the application slows down since it has not yet received ACKs for
the frames already queued in the hardware. Since this ACK may take
more than 100ms, stopping the dev queues for entering PS at this
stage breaks applications, WMM test cases in my testing.
If there are frames already pending in the tx queue, postponing the
PS logic helps to avoid redundant queue stops. When power save is
enabled by default and in a noisy environment, this API certainly
helps in improving the average throughput.

Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Vivek Natarajan authored and John W. Linville committed Apr 12, 2011
1 parent 6fc3ba9 commit e8306f9
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 8 deletions.
4 changes: 4 additions & 0 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1819,6 +1819,9 @@ enum ieee80211_ampdu_mlme_action {
* @set_ringparam: Set tx and rx ring sizes.
*
* @get_ringparam: Get tx and rx ring current and maximum sizes.
*
* @tx_frames_pending: Check if there is any pending frame in the hardware
* queues before entering power save.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
Expand Down Expand Up @@ -1906,6 +1909,7 @@ struct ieee80211_ops {
int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);
void (*get_ringparam)(struct ieee80211_hw *hw,
u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
bool (*tx_frames_pending)(struct ieee80211_hw *hw);
};

/**
Expand Down
13 changes: 13 additions & 0 deletions net/mac80211/driver-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -552,4 +552,17 @@ static inline void drv_get_ringparam(struct ieee80211_local *local,
trace_drv_return_void(local);
}

static inline bool drv_tx_frames_pending(struct ieee80211_local *local)
{
bool ret = false;

might_sleep();

trace_drv_tx_frames_pending(local);
if (local->ops->tx_frames_pending)
ret = local->ops->tx_frames_pending(&local->hw);
trace_drv_return_bool(local, ret);

return ret;
}
#endif /* __MAC80211_DRIVER_OPS */
20 changes: 20 additions & 0 deletions net/mac80211/driver-trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ TRACE_EVENT(drv_return_int,
TP_printk(LOCAL_PR_FMT " - %d", LOCAL_PR_ARG, __entry->ret)
);

TRACE_EVENT(drv_return_bool,
TP_PROTO(struct ieee80211_local *local, bool ret),
TP_ARGS(local, ret),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(bool, ret)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->ret = ret;
),
TP_printk(LOCAL_PR_FMT " - %s", LOCAL_PR_ARG, (__entry->ret) ?
"true" : "false")
);

TRACE_EVENT(drv_return_u64,
TP_PROTO(struct ieee80211_local *local, u64 ret),
TP_ARGS(local, ret),
Expand Down Expand Up @@ -964,6 +979,11 @@ TRACE_EVENT(drv_get_ringparam,
)
);

DEFINE_EVENT(local_only_evt, drv_tx_frames_pending,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)
);

DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)
Expand Down
17 changes: 9 additions & 8 deletions net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -761,15 +761,16 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
(!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) {
netif_tx_stop_all_queues(sdata->dev);
/*
* Flush all the frames queued in the driver before
* going to power save
*/
drv_flush(local, false);
ieee80211_send_nullfunc(local, sdata, 1);

/* Flush once again to get the tx status of nullfunc frame */
drv_flush(local, false);
if (drv_tx_frames_pending(local))
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(
local->hw.conf.dynamic_ps_timeout));
else {
ieee80211_send_nullfunc(local, sdata, 1);
/* Flush to get the tx status of nullfunc frame */
drv_flush(local, false);
}
}

if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
Expand Down

0 comments on commit e8306f9

Please sign in to comment.