linux/net/mac80211/pm.c
<<
>>
Prefs
   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
   9int __ieee80211_suspend(struct ieee80211_hw *hw)
  10{
  11        struct ieee80211_local *local = hw_to_local(hw);
  12        struct ieee80211_sub_if_data *sdata;
  13        struct ieee80211_if_init_conf conf;
  14        struct sta_info *sta;
  15        unsigned long flags;
  16
  17        ieee80211_scan_cancel(local);
  18
  19        ieee80211_stop_queues_by_reason(hw,
  20                        IEEE80211_QUEUE_STOP_REASON_SUSPEND);
  21
  22        /* flush out all packets */
  23        synchronize_net();
  24
  25        local->quiescing = true;
  26        /* make quiescing visible to timers everywhere */
  27        mb();
  28
  29        flush_workqueue(local->workqueue);
  30
  31        /* Don't try to run timers while suspended. */
  32        del_timer_sync(&local->sta_cleanup);
  33
  34         /*
  35         * Note that this particular timer doesn't need to be
  36         * restarted at resume.
  37         */
  38        cancel_work_sync(&local->dynamic_ps_enable_work);
  39        del_timer_sync(&local->dynamic_ps_timer);
  40
  41        /* disable keys */
  42        list_for_each_entry(sdata, &local->interfaces, list)
  43                ieee80211_disable_keys(sdata);
  44
  45        /* Tear down aggregation sessions */
  46
  47        rcu_read_lock();
  48
  49        if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
  50                list_for_each_entry_rcu(sta, &local->sta_list, list) {
  51                        set_sta_flags(sta, WLAN_STA_SUSPEND);
  52                        ieee80211_sta_tear_down_BA_sessions(sta);
  53                }
  54        }
  55
  56        rcu_read_unlock();
  57
  58        /* remove STAs */
  59        spin_lock_irqsave(&local->sta_lock, flags);
  60        list_for_each_entry(sta, &local->sta_list, list) {
  61                if (local->ops->sta_notify) {
  62                        sdata = sta->sdata;
  63                        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
  64                                sdata = container_of(sdata->bss,
  65                                             struct ieee80211_sub_if_data,
  66                                             u.ap);
  67
  68                        drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
  69                                       &sta->sta);
  70                }
  71
  72                mesh_plink_quiesce(sta);
  73        }
  74        spin_unlock_irqrestore(&local->sta_lock, flags);
  75
  76        /* remove all interfaces */
  77        list_for_each_entry(sdata, &local->interfaces, list) {
  78                switch(sdata->vif.type) {
  79                case NL80211_IFTYPE_STATION:
  80                        ieee80211_sta_quiesce(sdata);
  81                        break;
  82                case NL80211_IFTYPE_ADHOC:
  83                        ieee80211_ibss_quiesce(sdata);
  84                        break;
  85                case NL80211_IFTYPE_MESH_POINT:
  86                        ieee80211_mesh_quiesce(sdata);
  87                        break;
  88                case NL80211_IFTYPE_AP_VLAN:
  89                case NL80211_IFTYPE_MONITOR:
  90                        /* don't tell driver about this */
  91                        continue;
  92                default:
  93                        break;
  94                }
  95
  96                if (!netif_running(sdata->dev))
  97                        continue;
  98
  99                /* disable beaconing */
 100                ieee80211_bss_info_change_notify(sdata,
 101                        BSS_CHANGED_BEACON_ENABLED);
 102
 103                conf.vif = &sdata->vif;
 104                conf.type = sdata->vif.type;
 105                conf.mac_addr = sdata->dev->dev_addr;
 106                drv_remove_interface(local, &conf);
 107        }
 108
 109        /* stop hardware - this must stop RX */
 110        if (local->open_count)
 111                ieee80211_stop_device(local);
 112
 113        local->suspended = true;
 114        /* need suspended to be visible before quiescing is false */
 115        barrier();
 116        local->quiescing = false;
 117
 118        return 0;
 119}
 120
 121/*
 122 * __ieee80211_resume() is a static inline which just calls
 123 * ieee80211_reconfig(), which is also needed for hardware
 124 * hang/firmware failure/etc. recovery.
 125 */
 126
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.