aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-04-16 07:17:25 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-22 16:57:16 -0400
commit10f644a47b76d3e61b98f2d02ce9690b94c51ee5 (patch)
treefc344d0f888ea0b97608cd53eec1d2dc17672087
parent965bedadc01d34027455d5d5b67063ef0209c955 (diff)
mac80211: disable powersave if pm_qos asks for low latency
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>
-rw-r--r--include/linux/ieee80211.h9
-rw-r--r--net/mac80211/ieee80211_i.h5
-rw-r--r--net/mac80211/iface.c4
-rw-r--r--net/mac80211/main.c31
-rw-r--r--net/mac80211/mlme.c36
-rw-r--r--net/mac80211/wext.c2
6 files changed, 72 insertions, 15 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 4b501b48ce86..53563d53b5ad 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1383,4 +1383,13 @@ static inline int ieee80211_freq_to_ofdm_chan(int s_freq, int freq)
1383 return -1; 1383 return -1;
1384} 1384}
1385 1385
1386/**
1387 * ieee80211_tu_to_usec - convert time units (TU) to microseconds
1388 * @tu: the TUs
1389 */
1390static inline unsigned long ieee80211_tu_to_usec(unsigned long tu)
1391{
1392 return 1024 * tu;
1393}
1394
1386#endif /* LINUX_IEEE80211_H */ 1395#endif /* LINUX_IEEE80211_H */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ff40dd7b523a..b1d18d967d8c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -750,6 +750,7 @@ struct ieee80211_local {
750 struct work_struct dynamic_ps_enable_work; 750 struct work_struct dynamic_ps_enable_work;
751 struct work_struct dynamic_ps_disable_work; 751 struct work_struct dynamic_ps_disable_work;
752 struct timer_list dynamic_ps_timer; 752 struct timer_list dynamic_ps_timer;
753 struct notifier_block network_latency_notifier;
753 754
754 int user_power_level; /* in dBm */ 755 int user_power_level; /* in dBm */
755 int power_constr_level; /* in dBm */ 756 int power_constr_level; /* in dBm */
@@ -938,7 +939,9 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason
938int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); 939int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason);
939void ieee80211_send_pspoll(struct ieee80211_local *local, 940void ieee80211_send_pspoll(struct ieee80211_local *local,
940 struct ieee80211_sub_if_data *sdata); 941 struct ieee80211_sub_if_data *sdata);
941void ieee80211_recalc_ps(struct ieee80211_local *local); 942void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
943int ieee80211_max_network_latency(struct notifier_block *nb,
944 unsigned long data, void *dummy);
942 945
943/* IBSS code */ 946/* IBSS code */
944int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata); 947int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 6240f76e2a43..5d60deb219d3 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -317,7 +317,7 @@ static int ieee80211_open(struct net_device *dev)
317 ieee80211_set_wmm_default(sdata); 317 ieee80211_set_wmm_default(sdata);
318 } 318 }
319 319
320 ieee80211_recalc_ps(local); 320 ieee80211_recalc_ps(local, -1);
321 321
322 /* 322 /*
323 * ieee80211_sta_work is disabled while network interface 323 * ieee80211_sta_work is disabled while network interface
@@ -574,7 +574,7 @@ static int ieee80211_stop(struct net_device *dev)
574 hw_reconf_flags = 0; 574 hw_reconf_flags = 0;
575 } 575 }
576 576
577 ieee80211_recalc_ps(local); 577 ieee80211_recalc_ps(local, -1);
578 578
579 /* do after stop to avoid reconfiguring when we stop anyway */ 579 /* do after stop to avoid reconfiguring when we stop anyway */
580 if (hw_reconf_flags) 580 if (hw_reconf_flags)
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 80c0e28bf549..049ce8639806 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -21,6 +21,7 @@
21#include <linux/wireless.h> 21#include <linux/wireless.h>
22#include <linux/rtnetlink.h> 22#include <linux/rtnetlink.h>
23#include <linux/bitmap.h> 23#include <linux/bitmap.h>
24#include <linux/pm_qos_params.h>
24#include <net/net_namespace.h> 25#include <net/net_namespace.h>
25#include <net/cfg80211.h> 26#include <net/cfg80211.h>
26 27
@@ -1038,25 +1039,38 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
1038 } 1039 }
1039 } 1040 }
1040 1041
1042 local->network_latency_notifier.notifier_call =
1043 ieee80211_max_network_latency;
1044 result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
1045 &local->network_latency_notifier);
1046
1047 if (result) {
1048 rtnl_lock();
1049 goto fail_pm_qos;
1050 }
1051
1041 return 0; 1052 return 0;
1042 1053
1043fail_wep: 1054 fail_pm_qos:
1055 ieee80211_led_exit(local);
1056 ieee80211_remove_interfaces(local);
1057 fail_wep:
1044 rate_control_deinitialize(local); 1058 rate_control_deinitialize(local);
1045fail_rate: 1059 fail_rate:
1046 unregister_netdevice(local->mdev); 1060 unregister_netdevice(local->mdev);
1047 local->mdev = NULL; 1061 local->mdev = NULL;
1048fail_dev: 1062 fail_dev:
1049 rtnl_unlock(); 1063 rtnl_unlock();
1050 sta_info_stop(local); 1064 sta_info_stop(local);
1051fail_sta_info: 1065 fail_sta_info:
1052 debugfs_hw_del(local); 1066 debugfs_hw_del(local);
1053 destroy_workqueue(local->hw.workqueue); 1067 destroy_workqueue(local->hw.workqueue);
1054fail_workqueue: 1068 fail_workqueue:
1055 if (local->mdev) 1069 if (local->mdev)
1056 free_netdev(local->mdev); 1070 free_netdev(local->mdev);
1057fail_mdev_alloc: 1071 fail_mdev_alloc:
1058 wiphy_unregister(local->hw.wiphy); 1072 wiphy_unregister(local->hw.wiphy);
1059fail_wiphy_register: 1073 fail_wiphy_register:
1060 kfree(local->int_scan_req.channels); 1074 kfree(local->int_scan_req.channels);
1061 return result; 1075 return result;
1062} 1076}
@@ -1069,6 +1083,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
1069 tasklet_kill(&local->tx_pending_tasklet); 1083 tasklet_kill(&local->tx_pending_tasklet);
1070 tasklet_kill(&local->tasklet); 1084 tasklet_kill(&local->tasklet);
1071 1085
1086 pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
1087 &local->network_latency_notifier);
1088
1072 rtnl_lock(); 1089 rtnl_lock();
1073 1090
1074 /* 1091 /*
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 06d9a1d23252..c39a214e7ad0 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -17,6 +17,7 @@
17#include <linux/if_arp.h> 17#include <linux/if_arp.h>
18#include <linux/etherdevice.h> 18#include <linux/etherdevice.h>
19#include <linux/rtnetlink.h> 19#include <linux/rtnetlink.h>
20#include <linux/pm_qos_params.h>
20#include <net/mac80211.h> 21#include <net/mac80211.h>
21#include <asm/unaligned.h> 22#include <asm/unaligned.h>
22 23
@@ -515,7 +516,7 @@ static void ieee80211_change_ps(struct ieee80211_local *local)
515} 516}
516 517
517/* need to hold RTNL or interface lock */ 518/* need to hold RTNL or interface lock */
518void ieee80211_recalc_ps(struct ieee80211_local *local) 519void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
519{ 520{
520 struct ieee80211_sub_if_data *sdata, *found = NULL; 521 struct ieee80211_sub_if_data *sdata, *found = NULL;
521 int count = 0; 522 int count = 0;
@@ -534,10 +535,22 @@ void ieee80211_recalc_ps(struct ieee80211_local *local)
534 count++; 535 count++;
535 } 536 }
536 537
537 if (count == 1 && found->u.mgd.powersave) 538 if (count == 1 && found->u.mgd.powersave) {
538 local->ps_sdata = found; 539 s32 beaconint_us;
539 else 540
541 if (latency < 0)
542 latency = pm_qos_requirement(PM_QOS_NETWORK_LATENCY);
543
544 beaconint_us = ieee80211_tu_to_usec(
545 found->vif.bss_conf.beacon_int);
546
547 if (beaconint_us > latency)
548 local->ps_sdata = NULL;
549 else
550 local->ps_sdata = found;
551 } else {
540 local->ps_sdata = NULL; 552 local->ps_sdata = NULL;
553 }
541 554
542 ieee80211_change_ps(local); 555 ieee80211_change_ps(local);
543} 556}
@@ -2324,3 +2337,18 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
2324 ieee80211_restart_sta_timer(sdata); 2337 ieee80211_restart_sta_timer(sdata);
2325 rcu_read_unlock(); 2338 rcu_read_unlock();
2326} 2339}
2340
2341int ieee80211_max_network_latency(struct notifier_block *nb,
2342 unsigned long data, void *dummy)
2343{
2344 s32 latency_usec = (s32) data;
2345 struct ieee80211_local *local =
2346 container_of(nb, struct ieee80211_local,
2347 network_latency_notifier);
2348
2349 mutex_lock(&local->iflist_mtx);
2350 ieee80211_recalc_ps(local, latency_usec);
2351 mutex_unlock(&local->iflist_mtx);
2352
2353 return 0;
2354}
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 81f63e57027f..1c4664b8b1a0 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -789,7 +789,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
789 ieee80211_hw_config(local, 789 ieee80211_hw_config(local,
790 IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); 790 IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT);
791 791
792 ieee80211_recalc_ps(local); 792 ieee80211_recalc_ps(local, -1);
793 793
794 return 0; 794 return 0;
795} 795}