pm.c
Go to the documentation of this file.
00001 #include <net/mac80211.h>
00002 #include <net/rtnetlink.h>
00003 
00004 #include "ieee80211_i.h"
00005 #include "mesh.h"
00006 #include "driver-ops.h"
00007 #include "led.h"
00008 
00009 /* return value indicates whether the driver should be further notified */
00010 static bool ieee80211_quiesce(struct ieee80211_sub_if_data *sdata)
00011 {
00012         switch (sdata->vif.type) {
00013         case NL80211_IFTYPE_STATION:
00014                 ieee80211_sta_quiesce(sdata);
00015                 return true;
00016         case NL80211_IFTYPE_ADHOC:
00017                 ieee80211_ibss_quiesce(sdata);
00018                 return true;
00019         case NL80211_IFTYPE_MESH_POINT:
00020                 ieee80211_mesh_quiesce(sdata);
00021                 return true;
00022         case NL80211_IFTYPE_AP_VLAN:
00023         case NL80211_IFTYPE_MONITOR:
00024                 /* don't tell driver about this */
00025                 return false;
00026         default:
00027                 return true;
00028         }
00029 }
00030 
00031 int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
00032 {
00033         struct ieee80211_local *local = hw_to_local(hw);
00034         struct ieee80211_sub_if_data *sdata;
00035         struct sta_info *sta;
00036 
00037         if (!local->open_count)
00038                 goto suspend;
00039 
00040         ieee80211_scan_cancel(local);
00041 
00042         if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
00043                 mutex_lock(&local->sta_mtx);
00044                 list_for_each_entry(sta, &local->sta_list, list) {
00045                         set_sta_flag(sta, WLAN_STA_BLOCK_BA);
00046                         ieee80211_sta_tear_down_BA_sessions(sta, true);
00047                 }
00048                 mutex_unlock(&local->sta_mtx);
00049         }
00050 
00051         ieee80211_stop_queues_by_reason(hw,
00052                         IEEE80211_QUEUE_STOP_REASON_SUSPEND);
00053 
00054         /* flush out all packets */
00055         synchronize_net();
00056 
00057         drv_flush(local, false);
00058 
00059         local->quiescing = true;
00060         /* make quiescing visible to timers everywhere */
00061         mb();
00062 
00063         flush_workqueue(local->workqueue);
00064 
00065         /* Don't try to run timers while suspended. */
00066         del_timer_sync(&local->sta_cleanup);
00067 
00068          /*
00069          * Note that this particular timer doesn't need to be
00070          * restarted at resume.
00071          */
00072         cancel_work_sync(&local->dynamic_ps_enable_work);
00073         del_timer_sync(&local->dynamic_ps_timer);
00074 
00075         local->wowlan = wowlan && local->open_count;
00076         if (local->wowlan) {
00077                 int err = drv_suspend(local, wowlan);
00078                 if (err < 0) {
00079                         local->quiescing = false;
00080                         return err;
00081                 } else if (err > 0) {
00082                         WARN_ON(err != 1);
00083                         local->wowlan = false;
00084                 } else {
00085                         list_for_each_entry(sdata, &local->interfaces, list) {
00086                                 cancel_work_sync(&sdata->work);
00087                                 ieee80211_quiesce(sdata);
00088                         }
00089                         goto suspend;
00090                 }
00091         }
00092 
00093         /* disable keys */
00094         list_for_each_entry(sdata, &local->interfaces, list)
00095                 ieee80211_disable_keys(sdata);
00096 
00097         /* tear down aggregation sessions and remove STAs */
00098         mutex_lock(&local->sta_mtx);
00099         list_for_each_entry(sta, &local->sta_list, list) {
00100                 if (sta->uploaded) {
00101                         enum ieee80211_sta_state state;
00102 
00103                         state = sta->sta_state;
00104                         for (; state > IEEE80211_STA_NOTEXIST; state--)
00105                                 WARN_ON(drv_sta_state(local, sta->sdata, sta,
00106                                                       state, state - 1));
00107                 }
00108 
00109                 mesh_plink_quiesce(sta);
00110         }
00111         mutex_unlock(&local->sta_mtx);
00112 
00113         /* remove all interfaces */
00114         list_for_each_entry(sdata, &local->interfaces, list) {
00115                 cancel_work_sync(&sdata->work);
00116 
00117                 if (!ieee80211_quiesce(sdata))
00118                         continue;
00119 
00120                 if (!ieee80211_sdata_running(sdata))
00121                         continue;
00122 
00123                 /* disable beaconing */
00124                 ieee80211_bss_info_change_notify(sdata,
00125                         BSS_CHANGED_BEACON_ENABLED);
00126 
00127                 drv_remove_interface(local, sdata);
00128         }
00129 
00130         sdata = rtnl_dereference(local->monitor_sdata);
00131         if (sdata)
00132                 drv_remove_interface(local, sdata);
00133 
00134         /* stop hardware - this must stop RX */
00135         if (local->open_count)
00136                 ieee80211_stop_device(local);
00137 
00138  suspend:
00139         local->suspended = true;
00140         /* need suspended to be visible before quiescing is false */
00141         barrier();
00142         local->quiescing = false;
00143 
00144         return 0;
00145 }
00146 
00147 /*
00148  * __ieee80211_resume() is a static inline which just calls
00149  * ieee80211_reconfig(), which is also needed for hardware
00150  * hang/firmware failure/etc. recovery.
00151  */


ros_rt_wmp
Author(s): Danilo Tardioli, dantard@unizar.es
autogenerated on Fri Jan 3 2014 12:07:55