summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2014-10-28 16:56:06 +0300
committerJohn W. Linville <linville@tuxdriver.com>2014-10-30 22:24:50 +0300
commitb9a82f892e2a143788d6a4e9fa121837ae1c9a8d (patch)
tree0b4941ad416f3f1b8aac6fd66c9a41dba76d76cd /drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
parent330b4e4be937bf0ef126e01323f2756645b92c06 (diff)
downloadlinux-b9a82f892e2a143788d6a4e9fa121837ae1c9a8d.tar.xz
brcmfmac: Add wowl patterns support.
Reviewed-by: Arend Van Spriel <arend@broadcom.com> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com> Signed-off-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c66
1 files changed, 58 insertions, 8 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 28fa25b509db..fcadbe3c38d6 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -2779,6 +2779,44 @@ static __always_inline void brcmf_delay(u32 ms)
}
}
+static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
+ u8 *pattern, u32 patternsize, u8 *mask,
+ u32 packet_offset)
+{
+ struct brcmf_fil_wowl_pattern_le *filter;
+ u32 masksize;
+ u32 patternoffset;
+ u8 *buf;
+ u32 bufsize;
+ s32 ret;
+
+ masksize = (patternsize + 7) / 8;
+ patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
+
+ bufsize = sizeof(*filter) + patternsize + masksize;
+ buf = kzalloc(bufsize, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ filter = (struct brcmf_fil_wowl_pattern_le *)buf;
+
+ memcpy(filter->cmd, cmd, 4);
+ filter->masksize = cpu_to_le32(masksize);
+ filter->offset = cpu_to_le32(packet_offset);
+ filter->patternoffset = cpu_to_le32(patternoffset);
+ filter->patternsize = cpu_to_le32(patternsize);
+ filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
+
+ if ((mask) && (masksize))
+ memcpy(buf + sizeof(*filter), mask, masksize);
+ if ((pattern) && (patternsize))
+ memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
+
+ ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
+
+ kfree(buf);
+ return ret;
+}
+
static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
@@ -2788,10 +2826,11 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
brcmf_dbg(TRACE, "Enter\n");
if (cfg->wowl_enabled) {
+ brcmf_configure_arp_offload(ifp, true);
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);
+ brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
cfg->wowl_enabled = false;
}
return 0;
@@ -2802,21 +2841,29 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
struct cfg80211_wowlan *wowl)
{
u32 wowl_config;
+ u32 i;
brcmf_dbg(TRACE, "Suspend, wowl config.\n");
+ brcmf_configure_arp_offload(ifp, false);
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.
- */
+ wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
if (wowl->magic_pkt)
- wowl_config |= WL_WOWL_MAGIC;
+ wowl_config |= BRCMF_WOWL_MAGIC;
+ if ((wowl->patterns) && (wowl->n_patterns)) {
+ wowl_config |= BRCMF_WOWL_NET;
+ for (i = 0; i < wowl->n_patterns; i++) {
+ brcmf_config_wowl_pattern(ifp, "add",
+ (u8 *)wowl->patterns[i].pattern,
+ wowl->patterns[i].pattern_len,
+ (u8 *)wowl->patterns[i].mask,
+ wowl->patterns[i].pkt_offset);
+ }
+ }
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);
@@ -5440,10 +5487,13 @@ 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,
+ .n_patterns = BRCMF_WOWL_MAXPATTERNS,
+ .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
+ .pattern_min_len = 1,
+ .max_pkt_offset = 1500,
};
#endif