Skip to content

Commit

Permalink
mac80211: disable powersave if pm_qos asks for low latency
Browse files Browse the repository at this point in the history
When an application asks for a latency lower than the beacon interval
there's nothing we can do -- we need to stay awake and not have the
AP buffer frames for us. Add code to automatically calculate this
constraint in mac80211 so drivers need not concern themselves with it.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Johannes Berg authored and John W. Linville committed Apr 22, 2009
1 parent 965beda commit 10f644a
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 15 deletions.
9 changes: 9 additions & 0 deletions include/linux/ieee80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1383,4 +1383,13 @@ static inline int ieee80211_freq_to_ofdm_chan(int s_freq, int freq)
return -1;
}

/**
* ieee80211_tu_to_usec - convert time units (TU) to microseconds
* @tu: the TUs
*/
static inline unsigned long ieee80211_tu_to_usec(unsigned long tu)
{
return 1024 * tu;
}

#endif /* LINUX_IEEE80211_H */
5 changes: 4 additions & 1 deletion net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,7 @@ struct ieee80211_local {
struct work_struct dynamic_ps_enable_work;
struct work_struct dynamic_ps_disable_work;
struct timer_list dynamic_ps_timer;
struct notifier_block network_latency_notifier;

int user_power_level; /* in dBm */
int power_constr_level; /* in dBm */
Expand Down Expand Up @@ -938,7 +939,9 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason
int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason);
void ieee80211_send_pspoll(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_ps(struct ieee80211_local *local);
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
int ieee80211_max_network_latency(struct notifier_block *nb,
unsigned long data, void *dummy);

/* IBSS code */
int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata);
Expand Down
4 changes: 2 additions & 2 deletions net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ static int ieee80211_open(struct net_device *dev)
ieee80211_set_wmm_default(sdata);
}

ieee80211_recalc_ps(local);
ieee80211_recalc_ps(local, -1);

/*
* ieee80211_sta_work is disabled while network interface
Expand Down Expand Up @@ -574,7 +574,7 @@ static int ieee80211_stop(struct net_device *dev)
hw_reconf_flags = 0;
}

ieee80211_recalc_ps(local);
ieee80211_recalc_ps(local, -1);

/* do after stop to avoid reconfiguring when we stop anyway */
if (hw_reconf_flags)
Expand Down
31 changes: 24 additions & 7 deletions net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/wireless.h>
#include <linux/rtnetlink.h>
#include <linux/bitmap.h>
#include <linux/pm_qos_params.h>
#include <net/net_namespace.h>
#include <net/cfg80211.h>

Expand Down Expand Up @@ -1038,25 +1039,38 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
}

local->network_latency_notifier.notifier_call =
ieee80211_max_network_latency;
result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier);

if (result) {
rtnl_lock();
goto fail_pm_qos;
}

return 0;

fail_wep:
fail_pm_qos:
ieee80211_led_exit(local);
ieee80211_remove_interfaces(local);
fail_wep:
rate_control_deinitialize(local);
fail_rate:
fail_rate:
unregister_netdevice(local->mdev);
local->mdev = NULL;
fail_dev:
fail_dev:
rtnl_unlock();
sta_info_stop(local);
fail_sta_info:
fail_sta_info:
debugfs_hw_del(local);
destroy_workqueue(local->hw.workqueue);
fail_workqueue:
fail_workqueue:
if (local->mdev)
free_netdev(local->mdev);
fail_mdev_alloc:
fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy);
fail_wiphy_register:
fail_wiphy_register:
kfree(local->int_scan_req.channels);
return result;
}
Expand All @@ -1069,6 +1083,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);

pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier);

rtnl_lock();

/*
Expand Down
36 changes: 32 additions & 4 deletions net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include <linux/pm_qos_params.h>
#include <net/mac80211.h>
#include <asm/unaligned.h>

Expand Down Expand Up @@ -515,7 +516,7 @@ static void ieee80211_change_ps(struct ieee80211_local *local)
}

/* need to hold RTNL or interface lock */
void ieee80211_recalc_ps(struct ieee80211_local *local)
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
{
struct ieee80211_sub_if_data *sdata, *found = NULL;
int count = 0;
Expand All @@ -534,10 +535,22 @@ void ieee80211_recalc_ps(struct ieee80211_local *local)
count++;
}

if (count == 1 && found->u.mgd.powersave)
local->ps_sdata = found;
else
if (count == 1 && found->u.mgd.powersave) {
s32 beaconint_us;

if (latency < 0)
latency = pm_qos_requirement(PM_QOS_NETWORK_LATENCY);

beaconint_us = ieee80211_tu_to_usec(
found->vif.bss_conf.beacon_int);

if (beaconint_us > latency)
local->ps_sdata = NULL;
else
local->ps_sdata = found;
} else {
local->ps_sdata = NULL;
}

ieee80211_change_ps(local);
}
Expand Down Expand Up @@ -2324,3 +2337,18 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
ieee80211_restart_sta_timer(sdata);
rcu_read_unlock();
}

int ieee80211_max_network_latency(struct notifier_block *nb,
unsigned long data, void *dummy)
{
s32 latency_usec = (s32) data;
struct ieee80211_local *local =
container_of(nb, struct ieee80211_local,
network_latency_notifier);

mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, latency_usec);
mutex_unlock(&local->iflist_mtx);

return 0;
}
2 changes: 1 addition & 1 deletion net/mac80211/wext.c
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
ieee80211_hw_config(local,
IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT);

ieee80211_recalc_ps(local);
ieee80211_recalc_ps(local, -1);

return 0;
}
Expand Down

0 comments on commit 10f644a

Please sign in to comment.