diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-07-14 10:48:54 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-07-15 13:39:42 -0400 |
commit | 94f9b97be5b3bf67392e43fb7f567721b09142c2 (patch) | |
tree | 4ffbf7480eeb60baf40f63070439f96e9a92c7e7 | |
parent | 3f29c522184ffb44fd475fdbe6083023ab1506f8 (diff) |
mac80211: be more careful in suspend/resume
When suspending with all netdevs down, the device
is stopped but we still call a number of driver
callbacks that the driver might not expect. The
same happens during resume, we might call a few
callbacks without starting the driver. Fix this
by checking open_count around more things and
exiting quickly if it is 0.
Also, while at this I noticed that the coverage
class isn't reprogrammed after resume, so add
that.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | net/mac80211/pm.c | 3 | ||||
-rw-r--r-- | net/mac80211/util.c | 54 |
2 files changed, 31 insertions, 26 deletions
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index f87e993e713b..6326d3439861 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -34,6 +34,9 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
34 | struct ieee80211_sub_if_data *sdata; | 34 | struct ieee80211_sub_if_data *sdata; |
35 | struct sta_info *sta; | 35 | struct sta_info *sta; |
36 | 36 | ||
37 | if (!local->open_count) | ||
38 | goto suspend; | ||
39 | |||
37 | ieee80211_scan_cancel(local); | 40 | ieee80211_scan_cancel(local); |
38 | 41 | ||
39 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | 42 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5bfb80cba634..8c2df33fd7e8 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1157,27 +1157,37 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1157 | } | 1157 | } |
1158 | #endif | 1158 | #endif |
1159 | 1159 | ||
1160 | /* restart hardware */ | 1160 | /* setup fragmentation threshold */ |
1161 | if (local->open_count) { | 1161 | drv_set_frag_threshold(local, hw->wiphy->frag_threshold); |
1162 | /* | 1162 | |
1163 | * Upon resume hardware can sometimes be goofy due to | 1163 | /* setup RTS threshold */ |
1164 | * various platform / driver / bus issues, so restarting | 1164 | drv_set_rts_threshold(local, hw->wiphy->rts_threshold); |
1165 | * the device may at times not work immediately. Propagate | 1165 | |
1166 | * the error. | 1166 | /* reset coverage class */ |
1167 | */ | 1167 | drv_set_coverage_class(local, hw->wiphy->coverage_class); |
1168 | res = drv_start(local); | 1168 | |
1169 | if (res) { | 1169 | /* everything else happens only if HW was up & running */ |
1170 | WARN(local->suspended, "Hardware became unavailable " | 1170 | if (!local->open_count) |
1171 | "upon resume. This could be a software issue " | 1171 | goto wake_up; |
1172 | "prior to suspend or a hardware issue.\n"); | ||
1173 | return res; | ||
1174 | } | ||
1175 | 1172 | ||
1176 | ieee80211_led_radio(local, true); | 1173 | /* |
1177 | ieee80211_mod_tpt_led_trig(local, | 1174 | * Upon resume hardware can sometimes be goofy due to |
1178 | IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); | 1175 | * various platform / driver / bus issues, so restarting |
1176 | * the device may at times not work immediately. Propagate | ||
1177 | * the error. | ||
1178 | */ | ||
1179 | res = drv_start(local); | ||
1180 | if (res) { | ||
1181 | WARN(local->suspended, "Hardware became unavailable " | ||
1182 | "upon resume. This could be a software issue " | ||
1183 | "prior to suspend or a hardware issue.\n"); | ||
1184 | return res; | ||
1179 | } | 1185 | } |
1180 | 1186 | ||
1187 | ieee80211_led_radio(local, true); | ||
1188 | ieee80211_mod_tpt_led_trig(local, | ||
1189 | IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); | ||
1190 | |||
1181 | /* add interfaces */ | 1191 | /* add interfaces */ |
1182 | list_for_each_entry(sdata, &local->interfaces, list) { | 1192 | list_for_each_entry(sdata, &local->interfaces, list) { |
1183 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 1193 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
@@ -1201,12 +1211,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1201 | } | 1211 | } |
1202 | mutex_unlock(&local->sta_mtx); | 1212 | mutex_unlock(&local->sta_mtx); |
1203 | 1213 | ||
1204 | /* setup fragmentation threshold */ | ||
1205 | drv_set_frag_threshold(local, hw->wiphy->frag_threshold); | ||
1206 | |||
1207 | /* setup RTS threshold */ | ||
1208 | drv_set_rts_threshold(local, hw->wiphy->rts_threshold); | ||
1209 | |||
1210 | /* reconfigure hardware */ | 1214 | /* reconfigure hardware */ |
1211 | ieee80211_hw_config(local, ~0); | 1215 | ieee80211_hw_config(local, ~0); |
1212 | 1216 | ||
@@ -1287,9 +1291,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1287 | if (ieee80211_sdata_running(sdata)) | 1291 | if (ieee80211_sdata_running(sdata)) |
1288 | ieee80211_enable_keys(sdata); | 1292 | ieee80211_enable_keys(sdata); |
1289 | 1293 | ||
1290 | #ifdef CONFIG_PM | ||
1291 | wake_up: | 1294 | wake_up: |
1292 | #endif | ||
1293 | ieee80211_wake_queues_by_reason(hw, | 1295 | ieee80211_wake_queues_by_reason(hw, |
1294 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 1296 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
1295 | 1297 | ||