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                         sdata = sta->sdata;
00102                         if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
00103                                 sdata = container_of(sdata->bss,
00104                                              struct ieee80211_sub_if_data,
00105                                              u.ap);
00106 
00107                         drv_sta_remove(local, sdata, &sta->sta);
00108                 }
00109 
00110                 mesh_plink_quiesce(sta);
00111         }
00112         mutex_unlock(&local->sta_mtx);
00113 
00114         /* remove all interfaces */
00115         list_for_each_entry(sdata, &local->interfaces, list) {
00116                 cancel_work_sync(&sdata->work);
00117 
00118                 if (!ieee80211_quiesce(sdata))
00119                         continue;
00120 
00121                 if (!ieee80211_sdata_running(sdata))
00122                         continue;
00123 
00124                 /* disable beaconing */
00125                 ieee80211_bss_info_change_notify(sdata,
00126                         BSS_CHANGED_BEACON_ENABLED);
00127 
00128                 drv_remove_interface(local, &sdata->vif);
00129         }
00130 
00131         /* stop hardware - this must stop RX */
00132         if (local->open_count)
00133                 ieee80211_stop_device(local);
00134 
00135  suspend:
00136         local->suspended = true;
00137         /* need suspended to be visible before quiescing is false */
00138         barrier();
00139         local->quiescing = false;
00140 
00141         return 0;
00142 }
00143 
00144 /*
00145  * __ieee80211_resume() is a static inline which just calls
00146  * ieee80211_reconfig(), which is also needed for hardware
00147  * hang/firmware failure/etc. recovery.
00148  */


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