aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-04-29 06:26:17 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-06 15:14:51 -0400
commit5cff20e6c5a6591a79d3b027af222870f52bb550 (patch)
tree81b6ebb75c1dc87b65258e71526c1581d168156c /net
parent9955151df7c6452cae2ed9649f53d265c91cf155 (diff)
mac80211: tell driver when idle
When we aren't doing anything in mac80211, we can turn off much of the hardware, depending on the driver/hw. Not doing anything, aka being idle, means: * no monitor interfaces * no AP/mesh/wds interfaces * any station interfaces are in DISABLED state * any IBSS interfaces aren't trying to be in a network * we aren't trying to scan By creating a new function that verifies these conditions and calling it at strategic points where the states of those conditions change, we can easily make mac80211 tell the driver when we are idle to save power. Additionally, this fixes a small quirk where a recalculated powersave state is passed to the driver even if the hardware is about to stopped completely. This patch intentionally doesn't touch radio_enabled because that is currently implemented to be a soft rfkill which is inappropriate here when we need to be able to wake up with low latency. One thing I'm not entirely sure about is this: phy0: device no longer idle - in use wlan0: direct probe to AP 00:11:24:91:07:4d try 1 wlan0 direct probe responded wlan0: authenticate with AP 00:11:24:91:07:4d wlan0: authenticated > phy0: device now idle > phy0: device no longer idle - in use wlan0: associate with AP 00:11:24:91:07:4d wlan0: RX AssocResp from 00:11:24:91:07:4d (capab=0x401 status=0 aid=1) wlan0: associated Is it appropriate to go into idle state for a short time when we have just authenticated, but not associated yet? This happens only with the userspace SME, because we cannot really know how long it will wait before asking us to associate. Would going idle after a short timeout be more appropriate? We may need to revisit this, depending on what happens. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ibss.c5
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/iface.c78
-rw-r--r--net/mac80211/mlme.c11
-rw-r--r--net/mac80211/scan.c17
5 files changed, 101 insertions, 12 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index a8e23232267e..aa537681f87c 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -862,6 +862,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
862 862
863 sdata->u.ibss.ssid_len = params->ssid_len; 863 sdata->u.ibss.ssid_len = params->ssid_len;
864 864
865 ieee80211_recalc_idle(sdata->local);
866
865 set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); 867 set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
866 queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work); 868 queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work);
867 869
@@ -889,6 +891,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
889 891
890 skb_queue_purge(&sdata->u.ibss.skb_queue); 892 skb_queue_purge(&sdata->u.ibss.skb_queue);
891 memset(sdata->u.ibss.bssid, 0, ETH_ALEN); 893 memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
894 sdata->u.ibss.ssid_len = 0;
895
896 ieee80211_recalc_idle(sdata->local);
892 897
893 return 0; 898 return 0;
894} 899}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 236ea098bb6c..03e0d22603c8 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -985,6 +985,8 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
985 enum nl80211_iftype type); 985 enum nl80211_iftype type);
986void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); 986void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
987void ieee80211_remove_interfaces(struct ieee80211_local *local); 987void ieee80211_remove_interfaces(struct ieee80211_local *local);
988u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
989void ieee80211_recalc_idle(struct ieee80211_local *local);
988 990
989/* tx handling */ 991/* tx handling */
990void ieee80211_clear_tx_pending(struct ieee80211_local *local); 992void ieee80211_clear_tx_pending(struct ieee80211_local *local);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 256fa19e14ec..8b6daf0219f4 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -301,6 +301,8 @@ static int ieee80211_open(struct net_device *dev)
301 if (sdata->flags & IEEE80211_SDATA_PROMISC) 301 if (sdata->flags & IEEE80211_SDATA_PROMISC)
302 atomic_inc(&local->iff_promiscs); 302 atomic_inc(&local->iff_promiscs);
303 303
304 hw_reconf_flags |= __ieee80211_recalc_idle(local);
305
304 local->open_count++; 306 local->open_count++;
305 if (hw_reconf_flags) { 307 if (hw_reconf_flags) {
306 ieee80211_hw_config(local, hw_reconf_flags); 308 ieee80211_hw_config(local, hw_reconf_flags);
@@ -548,6 +550,10 @@ static int ieee80211_stop(struct net_device *dev)
548 550
549 sdata->bss = NULL; 551 sdata->bss = NULL;
550 552
553 hw_reconf_flags |= __ieee80211_recalc_idle(local);
554
555 ieee80211_recalc_ps(local, -1);
556
551 if (local->open_count == 0) { 557 if (local->open_count == 0) {
552 if (netif_running(local->mdev)) 558 if (netif_running(local->mdev))
553 dev_close(local->mdev); 559 dev_close(local->mdev);
@@ -565,8 +571,6 @@ static int ieee80211_stop(struct net_device *dev)
565 hw_reconf_flags = 0; 571 hw_reconf_flags = 0;
566 } 572 }
567 573
568 ieee80211_recalc_ps(local, -1);
569
570 /* do after stop to avoid reconfiguring when we stop anyway */ 574 /* do after stop to avoid reconfiguring when we stop anyway */
571 if (hw_reconf_flags) 575 if (hw_reconf_flags)
572 ieee80211_hw_config(local, hw_reconf_flags); 576 ieee80211_hw_config(local, hw_reconf_flags);
@@ -892,3 +896,73 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
892 unregister_netdevice(sdata->dev); 896 unregister_netdevice(sdata->dev);
893 } 897 }
894} 898}
899
900static u32 ieee80211_idle_off(struct ieee80211_local *local,
901 const char *reason)
902{
903 if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
904 return 0;
905
906#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
907 printk(KERN_DEBUG "%s: device no longer idle - %s\n",
908 wiphy_name(local->hw.wiphy), reason);
909#endif
910
911 local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
912 return IEEE80211_CONF_CHANGE_IDLE;
913}
914
915static u32 ieee80211_idle_on(struct ieee80211_local *local)
916{
917 if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
918 return 0;
919
920#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
921 printk(KERN_DEBUG "%s: device now idle\n",
922 wiphy_name(local->hw.wiphy));
923#endif
924
925 local->hw.conf.flags |= IEEE80211_CONF_IDLE;
926 return IEEE80211_CONF_CHANGE_IDLE;
927}
928
929u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
930{
931 struct ieee80211_sub_if_data *sdata;
932 int count = 0;
933
934 if (local->hw_scanning || local->sw_scanning)
935 return ieee80211_idle_off(local, "scanning");
936
937 list_for_each_entry(sdata, &local->interfaces, list) {
938 if (!netif_running(sdata->dev))
939 continue;
940 /* do not count disabled managed interfaces */
941 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
942 sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED)
943 continue;
944 /* do not count unused IBSS interfaces */
945 if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
946 !sdata->u.ibss.ssid_len)
947 continue;
948 /* count everything else */
949 count++;
950 }
951
952 if (!count)
953 return ieee80211_idle_on(local);
954 else
955 return ieee80211_idle_off(local, "in use");
956
957 return 0;
958}
959
960void ieee80211_recalc_idle(struct ieee80211_local *local)
961{
962 u32 chg;
963
964 mutex_lock(&local->iflist_mtx);
965 chg = __ieee80211_recalc_idle(local);
966 mutex_unlock(&local->iflist_mtx);
967 ieee80211_hw_config(local, chg);
968}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 2ded4766d014..5509c5aa6beb 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -890,6 +890,7 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata)
890 printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", 890 printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
891 sdata->dev->name, ifmgd->bssid); 891 sdata->dev->name, ifmgd->bssid);
892 ifmgd->state = IEEE80211_STA_MLME_DISABLED; 892 ifmgd->state = IEEE80211_STA_MLME_DISABLED;
893 ieee80211_recalc_idle(local);
893 cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); 894 cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid);
894 895
895 /* 896 /*
@@ -938,6 +939,7 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)
938 " timed out\n", 939 " timed out\n",
939 sdata->dev->name, ifmgd->bssid); 940 sdata->dev->name, ifmgd->bssid);
940 ifmgd->state = IEEE80211_STA_MLME_DISABLED; 941 ifmgd->state = IEEE80211_STA_MLME_DISABLED;
942 ieee80211_recalc_idle(local);
941 cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); 943 cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid);
942 ieee80211_rx_bss_remove(sdata, ifmgd->bssid, 944 ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
943 sdata->local->hw.conf.channel->center_freq, 945 sdata->local->hw.conf.channel->center_freq,
@@ -1041,6 +1043,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1041 1043
1042 rcu_read_unlock(); 1044 rcu_read_unlock();
1043 1045
1046 ieee80211_recalc_idle(local);
1047
1044 /* channel(_type) changes are handled by ieee80211_hw_config */ 1048 /* channel(_type) changes are handled by ieee80211_hw_config */
1045 local->oper_channel_type = NL80211_CHAN_NO_HT; 1049 local->oper_channel_type = NL80211_CHAN_NO_HT;
1046 1050
@@ -1121,6 +1125,7 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)
1121 " timed out\n", 1125 " timed out\n",
1122 sdata->dev->name, ifmgd->bssid); 1126 sdata->dev->name, ifmgd->bssid);
1123 ifmgd->state = IEEE80211_STA_MLME_DISABLED; 1127 ifmgd->state = IEEE80211_STA_MLME_DISABLED;
1128 ieee80211_recalc_idle(local);
1124 cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid); 1129 cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid);
1125 ieee80211_rx_bss_remove(sdata, ifmgd->bssid, 1130 ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
1126 sdata->local->hw.conf.channel->center_freq, 1131 sdata->local->hw.conf.channel->center_freq,
@@ -1141,6 +1146,7 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)
1141 printk(KERN_DEBUG "%s: mismatch in privacy configuration and " 1146 printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
1142 "mixed-cell disabled - abort association\n", sdata->dev->name); 1147 "mixed-cell disabled - abort association\n", sdata->dev->name);
1143 ifmgd->state = IEEE80211_STA_MLME_DISABLED; 1148 ifmgd->state = IEEE80211_STA_MLME_DISABLED;
1149 ieee80211_recalc_idle(local);
1144 return; 1150 return;
1145 } 1151 }
1146 1152
@@ -1279,6 +1285,7 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata)
1279 if (ifmgd->flags & IEEE80211_STA_EXT_SME) { 1285 if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
1280 /* Wait for SME to request association */ 1286 /* Wait for SME to request association */
1281 ifmgd->state = IEEE80211_STA_MLME_DISABLED; 1287 ifmgd->state = IEEE80211_STA_MLME_DISABLED;
1288 ieee80211_recalc_idle(sdata->local);
1282 } else 1289 } else
1283 ieee80211_associate(sdata); 1290 ieee80211_associate(sdata);
1284} 1291}
@@ -1515,6 +1522,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1515 if (ifmgd->flags & IEEE80211_STA_EXT_SME) { 1522 if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
1516 /* Wait for SME to decide what to do next */ 1523 /* Wait for SME to decide what to do next */
1517 ifmgd->state = IEEE80211_STA_MLME_DISABLED; 1524 ifmgd->state = IEEE80211_STA_MLME_DISABLED;
1525 ieee80211_recalc_idle(local);
1518 } 1526 }
1519 return; 1527 return;
1520 } 1528 }
@@ -2083,6 +2091,7 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata)
2083 } else { 2091 } else {
2084 ifmgd->assoc_scan_tries = 0; 2092 ifmgd->assoc_scan_tries = 0;
2085 ifmgd->state = IEEE80211_STA_MLME_DISABLED; 2093 ifmgd->state = IEEE80211_STA_MLME_DISABLED;
2094 ieee80211_recalc_idle(local);
2086 } 2095 }
2087 } 2096 }
2088 return -1; 2097 return -1;
@@ -2126,6 +2135,8 @@ static void ieee80211_sta_work(struct work_struct *work)
2126 } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request)) 2135 } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request))
2127 return; 2136 return;
2128 2137
2138 ieee80211_recalc_idle(local);
2139
2129 switch (ifmgd->state) { 2140 switch (ifmgd->state) {
2130 case IEEE80211_STA_MLME_DISABLED: 2141 case IEEE80211_STA_MLME_DISABLED:
2131 break; 2142 break;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 127bd54e0e38..c99ef8d04d3d 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -302,17 +302,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
302 /* we only have to protect scan_req and hw/sw scan */ 302 /* we only have to protect scan_req and hw/sw scan */
303 mutex_unlock(&local->scan_mtx); 303 mutex_unlock(&local->scan_mtx);
304 304
305 if (was_hw_scan) {
306 /*
307 * Somebody might have requested channel change during scan
308 * that we won't have acted upon, try now. ieee80211_hw_config
309 * will set the flag based on actual changes.
310 */
311 ieee80211_hw_config(local, 0);
312 goto done;
313 }
314
315 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); 305 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
306 if (was_hw_scan)
307 goto done;
316 308
317 netif_tx_lock_bh(local->mdev); 309 netif_tx_lock_bh(local->mdev);
318 netif_addr_lock(local->mdev); 310 netif_addr_lock(local->mdev);
@@ -351,6 +343,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
351 mutex_unlock(&local->iflist_mtx); 343 mutex_unlock(&local->iflist_mtx);
352 344
353 done: 345 done:
346 ieee80211_recalc_idle(local);
354 ieee80211_mlme_notify_scan_completed(local); 347 ieee80211_mlme_notify_scan_completed(local);
355 ieee80211_ibss_notify_scan_completed(local); 348 ieee80211_ibss_notify_scan_completed(local);
356 ieee80211_mesh_notify_scan_completed(local); 349 ieee80211_mesh_notify_scan_completed(local);
@@ -471,6 +464,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
471 * dependency, so that the scan completed calls 464 * dependency, so that the scan completed calls
472 * have more locking freedom. 465 * have more locking freedom.
473 */ 466 */
467
468 ieee80211_recalc_idle(local);
474 mutex_unlock(&local->scan_mtx); 469 mutex_unlock(&local->scan_mtx);
475 470
476 if (local->ops->hw_scan) 471 if (local->ops->hw_scan)
@@ -487,6 +482,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
487 } else 482 } else
488 local->sw_scanning = false; 483 local->sw_scanning = false;
489 484
485 ieee80211_recalc_idle(local);
486
490 local->scan_req = NULL; 487 local->scan_req = NULL;
491 local->scan_sdata = NULL; 488 local->scan_sdata = NULL;
492 } 489 }