brcmfmac: Add wowl wake indication report.
authorHante Meuleman <meuleman@broadcom.com>
Thu, 29 Oct 2015 19:33:19 +0000 (20:33 +0100)
committerKalle Valo <kvalo@codeaurora.org>
Thu, 26 Nov 2015 11:55:37 +0000 (13:55 +0200)
On wakeup of the system (resume) a wowl wakeup indication report
can be sent to cfg80211. This patch adds support for this. The
report specifies if the device was responsible for the wakeup
and if so, will specify the exact reason.

Reviewed-by: Arend Van Spriel <arend@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h

index 0c8cc7f3ad0b39114335bd44873a0d0c553a2e8a..998c52194b6ccc2682318f31e70c25ff894239d1 100644 (file)
@@ -3062,6 +3062,67 @@ static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
        return ret;
 }
 
+#ifdef CONFIG_PM
+
+static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
+{
+       struct brcmf_wowl_wakeind_le wake_ind_le;
+       struct cfg80211_wowlan_wakeup wakeup_data;
+       struct cfg80211_wowlan_wakeup *wakeup;
+       u32 wakeind;
+       s32 err;
+
+       err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
+                                      sizeof(wake_ind_le));
+       if (!err) {
+               brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
+               return;
+       }
+
+       wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
+       if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
+                      BRCMF_WOWL_RETR | BRCMF_WOWL_NET)) {
+               wakeup = &wakeup_data;
+               memset(&wakeup_data, 0, sizeof(wakeup_data));
+               wakeup_data.pattern_idx = -1;
+
+               if (wakeind & BRCMF_WOWL_MAGIC) {
+                       brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
+                       wakeup_data.magic_pkt = true;
+               }
+               if (wakeind & BRCMF_WOWL_DIS) {
+                       brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
+                       wakeup_data.disconnect = true;
+               }
+               if (wakeind & BRCMF_WOWL_BCN) {
+                       brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
+                       wakeup_data.disconnect = true;
+               }
+               if (wakeind & BRCMF_WOWL_RETR) {
+                       brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
+                       wakeup_data.disconnect = true;
+               }
+               if (wakeind & BRCMF_WOWL_NET) {
+                       brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
+                       /* For now always map to pattern 0, no API to get
+                        * correct information available at the moment.
+                        */
+                       wakeup_data.pattern_idx = 0;
+               }
+       } else {
+               wakeup = NULL;
+       }
+       cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
+}
+
+#else
+
+static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
+{
+}
+
+#endif /* CONFIG_PM */
+
 static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
@@ -3071,11 +3132,12 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
        brcmf_dbg(TRACE, "Enter\n");
 
        if (cfg->wowl_enabled) {
+               brcmf_report_wowl_wakeind(wiphy, ifp);
+               brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
+               brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
                brcmf_configure_arp_offload(ifp, true);
                brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
                                      cfg->pre_wowl_pmmode);
-               brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
-               brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
                cfg->wowl_enabled = false;
        }
        return 0;
@@ -3109,6 +3171,7 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
                                wowl->patterns[i].pkt_offset);
                }
        }
+       brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear", strlen("clear"));
        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);
index 50ff69dfa4b66f9f7b1857f086a34a107a78e280..92ee1ad6dd75dc30ce9768a83deaa02f01e79135 100644 (file)
@@ -634,4 +634,16 @@ struct brcmf_assoclist_le {
        u8 mac[BRCMF_MAX_ASSOCLIST][ETH_ALEN];
 };
 
+/**
+ * struct brcmf_wowl_wakeind_le - Wakeup indicators
+ *     Note: note both fields contain same information.
+ *
+ * @pci_wakeind: Whether PCI PMECSR PMEStatus bit was set.
+ * @ucode_wakeind: What wakeup-event indication was set by ucode
+ */
+struct brcmf_wowl_wakeind_le {
+       __le32 pci_wakeind;
+       __le32 ucode_wakeind;
+};
+
 #endif /* FWIL_TYPES_H_ */