Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pm.c
Go to the documentation of this file.
1 #include <net/mac80211.h>
2 #include <net/rtnetlink.h>
3 
4 #include "ieee80211_i.h"
5 #include "mesh.h"
6 #include "driver-ops.h"
7 #include "led.h"
8 
9 /* return value indicates whether the driver should be further notified */
10 static bool ieee80211_quiesce(struct ieee80211_sub_if_data *sdata)
11 {
12  switch (sdata->vif.type) {
14  ieee80211_sta_quiesce(sdata);
15  return true;
18  return true;
20  ieee80211_mesh_quiesce(sdata);
21  return true;
24  /* don't tell driver about this */
25  return false;
26  default:
27  return true;
28  }
29 }
30 
31 int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
32 {
33  struct ieee80211_local *local = hw_to_local(hw);
35  struct sta_info *sta;
36 
37  if (!local->open_count)
38  goto suspend;
39 
40  ieee80211_scan_cancel(local);
41 
43  mutex_lock(&local->sta_mtx);
44  list_for_each_entry(sta, &local->sta_list, list) {
45  set_sta_flag(sta, WLAN_STA_BLOCK_BA);
47  }
48  mutex_unlock(&local->sta_mtx);
49  }
50 
53 
54  /* flush out all packets */
56 
57  drv_flush(local, false);
58 
59  local->quiescing = true;
60  /* make quiescing visible to timers everywhere */
61  mb();
62 
63  flush_workqueue(local->workqueue);
64 
65  /* Don't try to run timers while suspended. */
66  del_timer_sync(&local->sta_cleanup);
67 
68  /*
69  * Note that this particular timer doesn't need to be
70  * restarted at resume.
71  */
74 
75  local->wowlan = wowlan && local->open_count;
76  if (local->wowlan) {
77  int err = drv_suspend(local, wowlan);
78  if (err < 0) {
79  local->quiescing = false;
80  local->wowlan = false;
82  mutex_lock(&local->sta_mtx);
84  &local->sta_list, list) {
85  clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
86  }
87  mutex_unlock(&local->sta_mtx);
88  }
91  return err;
92  } else if (err > 0) {
93  WARN_ON(err != 1);
94  local->wowlan = false;
95  } else {
96  list_for_each_entry(sdata, &local->interfaces, list) {
97  cancel_work_sync(&sdata->work);
98  ieee80211_quiesce(sdata);
99  }
100  goto suspend;
101  }
102  }
103 
104  /* disable keys */
105  list_for_each_entry(sdata, &local->interfaces, list)
106  ieee80211_disable_keys(sdata);
107 
108  /* tear down aggregation sessions and remove STAs */
109  mutex_lock(&local->sta_mtx);
110  list_for_each_entry(sta, &local->sta_list, list) {
111  if (sta->uploaded) {
113 
114  state = sta->sta_state;
115  for (; state > IEEE80211_STA_NOTEXIST; state--)
116  WARN_ON(drv_sta_state(local, sta->sdata, sta,
117  state, state - 1));
118  }
119 
120  mesh_plink_quiesce(sta);
121  }
122  mutex_unlock(&local->sta_mtx);
123 
124  /* remove all interfaces */
125  list_for_each_entry(sdata, &local->interfaces, list) {
126  cancel_work_sync(&sdata->work);
127 
128  if (!ieee80211_quiesce(sdata))
129  continue;
130 
131  if (!ieee80211_sdata_running(sdata))
132  continue;
133 
134  /* disable beaconing */
137 
138  drv_remove_interface(local, sdata);
139  }
140 
141  sdata = rtnl_dereference(local->monitor_sdata);
142  if (sdata)
143  drv_remove_interface(local, sdata);
144 
145  /* stop hardware - this must stop RX */
146  if (local->open_count)
147  ieee80211_stop_device(local);
148 
149  suspend:
150  local->suspended = true;
151  /* need suspended to be visible before quiescing is false */
152  barrier();
153  local->quiescing = false;
154 
155  return 0;
156 }
157 
158 /*
159  * __ieee80211_resume() is a static inline which just calls
160  * ieee80211_reconfig(), which is also needed for hardware
161  * hang/firmware failure/etc. recovery.
162  */