Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / net / mac80211 / pm.c
index 79a48f37d4092b27a88b8fa136f15a51812365f2..3d16f4e6174388f27e030f9612a64bbd752c04ea 100644 (file)
@@ -6,56 +6,37 @@
 #include "driver-ops.h"
 #include "led.h"
 
-/* return value indicates whether the driver should be further notified */
-static bool ieee80211_quiesce(struct ieee80211_sub_if_data *sdata)
-{
-       switch (sdata->vif.type) {
-       case NL80211_IFTYPE_STATION:
-               ieee80211_sta_quiesce(sdata);
-               return true;
-       case NL80211_IFTYPE_ADHOC:
-               ieee80211_ibss_quiesce(sdata);
-               return true;
-       case NL80211_IFTYPE_MESH_POINT:
-               ieee80211_mesh_quiesce(sdata);
-               return true;
-       case NL80211_IFTYPE_AP_VLAN:
-       case NL80211_IFTYPE_MONITOR:
-               /* don't tell driver about this */
-               return false;
-       default:
-               return true;
-       }
-}
-
 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;
 
        ieee80211_scan_cancel(local);
 
+       ieee80211_dfs_cac_cancel(local);
+
        if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
                mutex_lock(&local->sta_mtx);
                list_for_each_entry(sta, &local->sta_list, list) {
                        set_sta_flag(sta, WLAN_STA_BLOCK_BA);
-                       ieee80211_sta_tear_down_BA_sessions(sta, true);
+                       ieee80211_sta_tear_down_BA_sessions(
+                                       sta, AGG_STOP_LOCAL_REQUEST);
                }
                mutex_unlock(&local->sta_mtx);
        }
 
        ieee80211_stop_queues_by_reason(hw,
-                       IEEE80211_QUEUE_STOP_REASON_SUSPEND);
+                                       IEEE80211_MAX_QUEUE_MAP,
+                                       IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
        /* flush out all packets */
        synchronize_net();
 
-       drv_flush(local, false);
+       ieee80211_flush_queues(local, NULL);
 
        local->quiescing = true;
        /* make quiescing visible to timers everywhere */
@@ -88,24 +69,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) {
-                               cancel_work_sync(&sdata->work);
-                               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,74 +91,25 @@ 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) {
-               cancel_work_sync(&sdata->work);
-
-               if (!ieee80211_quiesce(sdata))
-                       continue;
-
                if (!ieee80211_sdata_running(sdata))
                        continue;
-
-               /* disable beaconing */
-               ieee80211_bss_info_change_notify(sdata,
-                       BSS_CHANGED_BEACON_ENABLED);
-
-               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);
-               }
-
+       if (sdata)
                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)
@@ -204,3 +129,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
  * ieee80211_reconfig(), which is also needed for hardware
  * hang/firmware failure/etc. recovery.
  */
+
+void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif,
+                                   struct cfg80211_wowlan_wakeup *wakeup,
+                                   gfp_t gfp)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       cfg80211_report_wowlan_wakeup(&sdata->wdev, wakeup, gfp);
+}
+EXPORT_SYMBOL(ieee80211_report_wowlan_wakeup);