brcmfmac: Add wowl support for PCIE devices.
[deliverable/linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / wl_cfg80211.c
index 6860501bc1794fc37ef3b206d842ba5b7127de8c..e9e18e1566dd46c9f72effd3039d97b39f85d3db 100644 (file)
@@ -37,6 +37,7 @@
 #include "fwil.h"
 #include "proto.h"
 #include "vendor.h"
+#include "dhd_bus.h"
 
 #define BRCMF_SCAN_IE_LEN_MAX          2048
 #define BRCMF_PNO_VERSION              2
@@ -2777,50 +2778,91 @@ static __always_inline void brcmf_delay(u32 ms)
 
 static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
 {
+       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct net_device *ndev = cfg_to_ndev(cfg);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+
        brcmf_dbg(TRACE, "Enter\n");
 
+       if (cfg->wowl_enabled) {
+               brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
+                                     cfg->pre_wowl_pmmode);
+               brcmf_fil_iovar_data_set(ifp, "wowl_pattern", "clr", 4);
+               brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
+               cfg->wowl_enabled = false;
+       }
        return 0;
 }
 
+static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
+                                struct brcmf_if *ifp,
+                                struct cfg80211_wowlan *wowl)
+{
+       u32 wowl_config;
+
+       brcmf_dbg(TRACE, "Suspend, wowl config.\n");
+
+       brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->pre_wowl_pmmode);
+       brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
+
+       wowl_config = 0;
+       if (wowl->disconnect)
+               wowl_config |= WL_WOWL_DIS | WL_WOWL_BCN | WL_WOWL_RETR;
+               /* Note: if "wowl" target and not "wowlpf" then wowl_bcn_loss
+                * should be configured. This paramater is not supported by
+                * wowlpf.
+                */
+       if (wowl->magic_pkt)
+               wowl_config |= WL_WOWL_MAGIC;
+       brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
+       brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
+       brcmf_bus_wowl_config(cfg->pub->bus_if, true);
+       cfg->wowl_enabled = true;
+}
+
 static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
-                                 struct cfg80211_wowlan *wow)
+                                 struct cfg80211_wowlan *wowl)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct net_device *ndev = cfg_to_ndev(cfg);
+       struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_cfg80211_vif *vif;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       /*
-        * if the primary net_device is not READY there is nothing
+       /* if the primary net_device is not READY there is nothing
         * we can do but pray resume goes smoothly.
         */
-       vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
-       if (!check_vif_up(vif))
+       if (!check_vif_up(ifp->vif))
                goto exit;
 
-       list_for_each_entry(vif, &cfg->vif_list, list) {
-               if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
-                       continue;
-               /*
-                * While going to suspend if associated with AP disassociate
-                * from AP to save power while system is in suspended state
-                */
-               brcmf_link_down(vif);
-
-               /* Make sure WPA_Supplicant receives all the event
-                * generated due to DISASSOC call to the fw to keep
-                * the state fw and WPA_Supplicant state consistent
-                */
-               brcmf_delay(500);
-       }
-
        /* end any scanning */
        if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
                brcmf_abort_scanning(cfg);
 
-       /* Turn off watchdog timer */
-       brcmf_set_mpc(netdev_priv(ndev), 1);
+       if (wowl == NULL) {
+               brcmf_bus_wowl_config(cfg->pub->bus_if, false);
+               list_for_each_entry(vif, &cfg->vif_list, list) {
+                       if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
+                               continue;
+                       /* While going to suspend if associated with AP
+                        * disassociate from AP to save power while system is
+                        * in suspended state
+                        */
+                       brcmf_link_down(vif);
+                       /* Make sure WPA_Supplicant receives all the event
+                        * generated due to DISASSOC call to the fw to keep
+                        * the state fw and WPA_Supplicant state consistent
+                        */
+                       brcmf_delay(500);
+               }
+               /* Configure MPC */
+               brcmf_set_mpc(ifp, 1);
+
+       } else {
+               /* Configure WOWL paramaters */
+               brcmf_configure_wowl(cfg, ifp, wowl);
+       }
 
 exit:
        brcmf_dbg(TRACE, "Exit\n");
@@ -5393,6 +5435,21 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
        wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
 }
 
+
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support brcmf_wowlan_support = {
+       .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+};
+#endif
+
+static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
+{
+#ifdef CONFIG_PM
+       /* wowl settings */
+       wiphy->wowlan = &brcmf_wowlan_support;
+#endif
+}
+
 static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
 {
        struct ieee80211_iface_combination ifc_combo;
@@ -5430,6 +5487,9 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
        wiphy->vendor_commands = brcmf_vendor_cmds;
        wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
 
+       if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
+               brcmf_wiphy_wowl_params(wiphy);
+
        return brcmf_setup_wiphybands(wiphy);
 }
 
This page took 0.035719 seconds and 5 git commands to generate.