diff options
author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2013-05-15 10:26:50 -0400 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2013-05-15 10:26:50 -0400 |
commit | 12e04ffcd93b25dfd726d46338c2ee7d23de556e (patch) | |
tree | f91479a62805619168994fd3ee55e3ffa23fc24e /net/mac80211/pm.c | |
parent | 9eff37a8713939f218ab8bf0dc93f1d67af7b8b4 (diff) | |
parent | f722406faae2d073cc1d01063d1123c35425939e (diff) |
Merge tag 'v3.10-rc1' into stable/for-linus-3.10
Linux 3.10-rc1
* tag 'v3.10-rc1': (12273 commits)
Linux 3.10-rc1
[SCSI] qla2xxx: Update firmware link in Kconfig file.
[SCSI] iscsi class, qla4xxx: fix sess/conn refcounting when find fns are used
[SCSI] sas: unify the pointlessly separated enums sas_dev_type and sas_device_type
[SCSI] pm80xx: thermal, sas controller config and error handling update
[SCSI] pm80xx: NCQ error handling changes
[SCSI] pm80xx: WWN Modification for PM8081/88/89 controllers
[SCSI] pm80xx: Changed module name and debug messages update
[SCSI] pm80xx: Firmware flash memory free fix, with addition of new memory region for it
[SCSI] pm80xx: SPC new firmware changes for device id 0x8081 alone
[SCSI] pm80xx: Added SPCv/ve specific hardware functionalities and relevant changes in common files
[SCSI] pm80xx: MSI-X implementation for using 64 interrupts
[SCSI] pm80xx: Updated common functions common for SPC and SPCv/ve
[SCSI] pm80xx: Multiple inbound/outbound queue configuration
[SCSI] pm80xx: Added SPCv/ve specific ids, variables and modify for SPC
[SCSI] lpfc: fix up Kconfig dependencies
[SCSI] Handle MLQUEUE busy response in scsi_send_eh_cmnd
dm cache: set config value
dm cache: move config fns
dm thin: generate event when metadata threshold passed
...
Diffstat (limited to 'net/mac80211/pm.c')
-rw-r--r-- | net/mac80211/pm.c | 132 |
1 files changed, 16 insertions, 116 deletions
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index d0275f34bf7..7fc5d0d8149 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -6,32 +6,11 @@ #include "driver-ops.h" #include "led.h" -/* return value indicates whether the driver should be further notified */ -static void ieee80211_quiesce(struct ieee80211_sub_if_data *sdata) -{ - switch (sdata->vif.type) { - case NL80211_IFTYPE_STATION: - ieee80211_sta_quiesce(sdata); - break; - case NL80211_IFTYPE_ADHOC: - ieee80211_ibss_quiesce(sdata); - break; - case NL80211_IFTYPE_MESH_POINT: - ieee80211_mesh_quiesce(sdata); - break; - default: - break; - } - - cancel_work_sync(&sdata->work); -} - int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; struct sta_info *sta; - struct ieee80211_chanctx *ctx; if (!local->open_count) goto suspend; @@ -40,6 +19,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ieee80211_dfs_cac_cancel(local); + ieee80211_roc_purge(local, NULL); + + ieee80211_del_virtual_monitor(local); + if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { @@ -51,12 +34,14 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) } ieee80211_stop_queues_by_reason(hw, - IEEE80211_QUEUE_STOP_REASON_SUSPEND); + IEEE80211_MAX_QUEUE_MAP, + IEEE80211_QUEUE_STOP_REASON_SUSPEND); - /* flush out all packets */ + /* flush out all packets and station cleanup call_rcu()s */ synchronize_net(); + rcu_barrier(); - drv_flush(local, false); + ieee80211_flush_queues(local, NULL); local->quiescing = true; /* make quiescing visible to timers everywhere */ @@ -89,23 +74,17 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) mutex_unlock(&local->sta_mtx); } ieee80211_wake_queues_by_reason(hw, + IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_SUSPEND); return err; } else if (err > 0) { WARN_ON(err != 1); - local->wowlan = false; + return err; } else { - list_for_each_entry(sdata, &local->interfaces, list) - if (ieee80211_sdata_running(sdata)) - ieee80211_quiesce(sdata); goto suspend; } } - /* disable keys */ - list_for_each_entry(sdata, &local->interfaces, list) - ieee80211_disable_keys(sdata); - /* tear down aggregation sessions and remove STAs */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { @@ -117,100 +96,21 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) WARN_ON(drv_sta_state(local, sta->sdata, sta, state, state - 1)); } - - mesh_plink_quiesce(sta); } mutex_unlock(&local->sta_mtx); /* remove all interfaces */ list_for_each_entry(sdata, &local->interfaces, list) { - static u8 zero_addr[ETH_ALEN] = {}; - u32 changed = 0; - if (!ieee80211_sdata_running(sdata)) continue; - - switch (sdata->vif.type) { - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_MONITOR: - /* skip these */ - continue; - case NL80211_IFTYPE_STATION: - if (sdata->vif.bss_conf.assoc) - changed = BSS_CHANGED_ASSOC | - BSS_CHANGED_BSSID | - BSS_CHANGED_IDLE; - break; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - if (sdata->vif.bss_conf.enable_beacon) - changed = BSS_CHANGED_BEACON_ENABLED; - break; - default: - break; - } - - ieee80211_quiesce(sdata); - - sdata->suspend_bss_conf = sdata->vif.bss_conf; - memset(&sdata->vif.bss_conf, 0, sizeof(sdata->vif.bss_conf)); - sdata->vif.bss_conf.idle = true; - if (sdata->suspend_bss_conf.bssid) - sdata->vif.bss_conf.bssid = zero_addr; - - /* disable beaconing or remove association */ - ieee80211_bss_info_change_notify(sdata, changed); - - if (sdata->vif.type == NL80211_IFTYPE_AP && - rcu_access_pointer(sdata->u.ap.beacon)) - drv_stop_ap(local, sdata); - - if (local->use_chanctx) { - struct ieee80211_chanctx_conf *conf; - - mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected( - sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); - if (conf) { - ctx = container_of(conf, - struct ieee80211_chanctx, - conf); - drv_unassign_vif_chanctx(local, sdata, ctx); - } - - mutex_unlock(&local->chanctx_mtx); - } - drv_remove_interface(local, sdata); - } - - sdata = rtnl_dereference(local->monitor_sdata); - if (sdata) { - if (local->use_chanctx) { - struct ieee80211_chanctx_conf *conf; - - mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected( - sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); - if (conf) { - ctx = container_of(conf, - struct ieee80211_chanctx, - conf); - drv_unassign_vif_chanctx(local, sdata, ctx); - } - - mutex_unlock(&local->chanctx_mtx); - } - drv_remove_interface(local, sdata); } - mutex_lock(&local->chanctx_mtx); - list_for_each_entry(ctx, &local->chanctx_list, list) - drv_remove_chanctx(local, ctx); - mutex_unlock(&local->chanctx_mtx); + /* + * We disconnected on all interfaces before suspend, all channel + * contexts should be released. + */ + WARN_ON(!list_empty(&local->chanctx_list)); /* stop hardware - this must stop RX */ if (local->open_count) |