]>
Commit | Line | Data |
---|---|---|
665af4fc BC |
1 | #include <net/mac80211.h> |
2 | #include <net/rtnetlink.h> | |
3 | ||
4 | #include "ieee80211_i.h" | |
24487981 | 5 | #include "driver-ops.h" |
665af4fc BC |
6 | #include "led.h" |
7 | ||
8 | int __ieee80211_suspend(struct ieee80211_hw *hw) | |
9 | { | |
10 | struct ieee80211_local *local = hw_to_local(hw); | |
11 | struct ieee80211_sub_if_data *sdata; | |
12 | struct ieee80211_if_init_conf conf; | |
13 | struct sta_info *sta; | |
7f0216a4 | 14 | unsigned long flags; |
665af4fc | 15 | |
25420604 JB |
16 | ieee80211_stop_queues_by_reason(hw, |
17 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | |
18 | ||
665af4fc BC |
19 | flush_workqueue(local->hw.workqueue); |
20 | ||
21 | /* disable keys */ | |
22 | list_for_each_entry(sdata, &local->interfaces, list) | |
23 | ieee80211_disable_keys(sdata); | |
24 | ||
722f069a S |
25 | /* Tear down aggregation sessions */ |
26 | ||
27 | rcu_read_lock(); | |
28 | ||
29 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | |
30 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | |
31 | set_sta_flags(sta, WLAN_STA_SUSPEND); | |
32 | ieee80211_sta_tear_down_BA_sessions(sta); | |
33 | } | |
34 | } | |
35 | ||
36 | rcu_read_unlock(); | |
37 | ||
665af4fc | 38 | /* remove STAs */ |
7f0216a4 JB |
39 | if (local->ops->sta_notify) { |
40 | spin_lock_irqsave(&local->sta_lock, flags); | |
41 | list_for_each_entry(sta, &local->sta_list, list) { | |
665af4fc BC |
42 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
43 | sdata = container_of(sdata->bss, | |
44 | struct ieee80211_sub_if_data, | |
45 | u.ap); | |
46 | ||
24487981 JB |
47 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, |
48 | &sta->sta); | |
665af4fc | 49 | } |
7f0216a4 | 50 | spin_unlock_irqrestore(&local->sta_lock, flags); |
665af4fc BC |
51 | } |
52 | ||
53 | /* remove all interfaces */ | |
54 | list_for_each_entry(sdata, &local->interfaces, list) { | |
665af4fc BC |
55 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
56 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | |
57 | netif_running(sdata->dev)) { | |
58 | conf.vif = &sdata->vif; | |
59 | conf.type = sdata->vif.type; | |
60 | conf.mac_addr = sdata->dev->dev_addr; | |
24487981 | 61 | drv_remove_interface(local, &conf); |
665af4fc BC |
62 | } |
63 | } | |
64 | ||
e874e658 BC |
65 | /* flush again, in case driver queued work */ |
66 | flush_workqueue(local->hw.workqueue); | |
67 | ||
665af4fc BC |
68 | /* stop hardware */ |
69 | if (local->open_count) { | |
70 | ieee80211_led_radio(local, false); | |
24487981 | 71 | drv_stop(local); |
665af4fc BC |
72 | } |
73 | return 0; | |
74 | } | |
75 | ||
f2753ddb JB |
76 | /* |
77 | * __ieee80211_resume() is a static inline which just calls | |
78 | * ieee80211_reconfig(), which is also needed for hardware | |
79 | * hang/firmware failure/etc. recovery. | |
80 | */ |