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>
This commit is contained in:
parent
330b4e4be9
commit
b9a82f892e
2 changed files with 120 additions and 35 deletions
|
@ -55,59 +55,63 @@
|
||||||
|
|
||||||
/* WOWL bits */
|
/* WOWL bits */
|
||||||
/* Wakeup on Magic packet: */
|
/* Wakeup on Magic packet: */
|
||||||
#define WL_WOWL_MAGIC (1 << 0)
|
#define BRCMF_WOWL_MAGIC (1 << 0)
|
||||||
/* Wakeup on Netpattern */
|
/* Wakeup on Netpattern */
|
||||||
#define WL_WOWL_NET (1 << 1)
|
#define BRCMF_WOWL_NET (1 << 1)
|
||||||
/* Wakeup on loss-of-link due to Disassoc/Deauth: */
|
/* Wakeup on loss-of-link due to Disassoc/Deauth: */
|
||||||
#define WL_WOWL_DIS (1 << 2)
|
#define BRCMF_WOWL_DIS (1 << 2)
|
||||||
/* Wakeup on retrograde TSF: */
|
/* Wakeup on retrograde TSF: */
|
||||||
#define WL_WOWL_RETR (1 << 3)
|
#define BRCMF_WOWL_RETR (1 << 3)
|
||||||
/* Wakeup on loss of beacon: */
|
/* Wakeup on loss of beacon: */
|
||||||
#define WL_WOWL_BCN (1 << 4)
|
#define BRCMF_WOWL_BCN (1 << 4)
|
||||||
/* Wakeup after test: */
|
/* Wakeup after test: */
|
||||||
#define WL_WOWL_TST (1 << 5)
|
#define BRCMF_WOWL_TST (1 << 5)
|
||||||
/* Wakeup after PTK refresh: */
|
/* Wakeup after PTK refresh: */
|
||||||
#define WL_WOWL_M1 (1 << 6)
|
#define BRCMF_WOWL_M1 (1 << 6)
|
||||||
/* Wakeup after receipt of EAP-Identity Req: */
|
/* Wakeup after receipt of EAP-Identity Req: */
|
||||||
#define WL_WOWL_EAPID (1 << 7)
|
#define BRCMF_WOWL_EAPID (1 << 7)
|
||||||
/* Wakeind via PME(0) or GPIO(1): */
|
/* Wakeind via PME(0) or GPIO(1): */
|
||||||
#define WL_WOWL_PME_GPIO (1 << 8)
|
#define BRCMF_WOWL_PME_GPIO (1 << 8)
|
||||||
/* need tkip phase 1 key to be updated by the driver: */
|
/* need tkip phase 1 key to be updated by the driver: */
|
||||||
#define WL_WOWL_NEEDTKIP1 (1 << 9)
|
#define BRCMF_WOWL_NEEDTKIP1 (1 << 9)
|
||||||
/* enable wakeup if GTK fails: */
|
/* enable wakeup if GTK fails: */
|
||||||
#define WL_WOWL_GTK_FAILURE (1 << 10)
|
#define BRCMF_WOWL_GTK_FAILURE (1 << 10)
|
||||||
/* support extended magic packets: */
|
/* support extended magic packets: */
|
||||||
#define WL_WOWL_EXTMAGPAT (1 << 11)
|
#define BRCMF_WOWL_EXTMAGPAT (1 << 11)
|
||||||
/* support ARP/NS/keepalive offloading: */
|
/* support ARP/NS/keepalive offloading: */
|
||||||
#define WL_WOWL_ARPOFFLOAD (1 << 12)
|
#define BRCMF_WOWL_ARPOFFLOAD (1 << 12)
|
||||||
/* read protocol version for EAPOL frames: */
|
/* read protocol version for EAPOL frames: */
|
||||||
#define WL_WOWL_WPA2 (1 << 13)
|
#define BRCMF_WOWL_WPA2 (1 << 13)
|
||||||
/* If the bit is set, use key rotaton: */
|
/* If the bit is set, use key rotaton: */
|
||||||
#define WL_WOWL_KEYROT (1 << 14)
|
#define BRCMF_WOWL_KEYROT (1 << 14)
|
||||||
/* If the bit is set, frm received was bcast frame: */
|
/* If the bit is set, frm received was bcast frame: */
|
||||||
#define WL_WOWL_BCAST (1 << 15)
|
#define BRCMF_WOWL_BCAST (1 << 15)
|
||||||
/* If the bit is set, scan offload is enabled: */
|
/* If the bit is set, scan offload is enabled: */
|
||||||
#define WL_WOWL_SCANOL (1 << 16)
|
#define BRCMF_WOWL_SCANOL (1 << 16)
|
||||||
/* Wakeup on tcpkeep alive timeout: */
|
/* Wakeup on tcpkeep alive timeout: */
|
||||||
#define WL_WOWL_TCPKEEP_TIME (1 << 17)
|
#define BRCMF_WOWL_TCPKEEP_TIME (1 << 17)
|
||||||
/* Wakeup on mDNS Conflict Resolution: */
|
/* Wakeup on mDNS Conflict Resolution: */
|
||||||
#define WL_WOWL_MDNS_CONFLICT (1 << 18)
|
#define BRCMF_WOWL_MDNS_CONFLICT (1 << 18)
|
||||||
/* Wakeup on mDNS Service Connect: */
|
/* Wakeup on mDNS Service Connect: */
|
||||||
#define WL_WOWL_MDNS_SERVICE (1 << 19)
|
#define BRCMF_WOWL_MDNS_SERVICE (1 << 19)
|
||||||
/* tcp keepalive got data: */
|
/* tcp keepalive got data: */
|
||||||
#define WL_WOWL_TCPKEEP_DATA (1 << 20)
|
#define BRCMF_WOWL_TCPKEEP_DATA (1 << 20)
|
||||||
/* Firmware died in wowl mode: */
|
/* Firmware died in wowl mode: */
|
||||||
#define WL_WOWL_FW_HALT (1 << 21)
|
#define BRCMF_WOWL_FW_HALT (1 << 21)
|
||||||
/* Enable detection of radio button changes: */
|
/* Enable detection of radio button changes: */
|
||||||
#define WL_WOWL_ENAB_HWRADIO (1 << 22)
|
#define BRCMF_WOWL_ENAB_HWRADIO (1 << 22)
|
||||||
/* Offloads detected MIC failure(s): */
|
/* Offloads detected MIC failure(s): */
|
||||||
#define WL_WOWL_MIC_FAIL (1 << 23)
|
#define BRCMF_WOWL_MIC_FAIL (1 << 23)
|
||||||
/* Wakeup in Unassociated state (Net/Magic Pattern): */
|
/* Wakeup in Unassociated state (Net/Magic Pattern): */
|
||||||
#define WL_WOWL_UNASSOC (1 << 24)
|
#define BRCMF_WOWL_UNASSOC (1 << 24)
|
||||||
/* Wakeup if received matched secured pattern: */
|
/* Wakeup if received matched secured pattern: */
|
||||||
#define WL_WOWL_SECURE (1 << 25)
|
#define BRCMF_WOWL_SECURE (1 << 25)
|
||||||
/* Link Down indication in WoWL mode: */
|
/* Link Down indication in WoWL mode: */
|
||||||
#define WL_WOWL_LINKDOWN (1 << 31)
|
#define BRCMF_WOWL_LINKDOWN (1 << 31)
|
||||||
|
|
||||||
|
#define BRCMF_WOWL_MAXPATTERNS 8
|
||||||
|
#define BRCMF_WOWL_MAXPATTERNSIZE 128
|
||||||
|
|
||||||
|
|
||||||
/* join preference types for join_pref iovar */
|
/* join preference types for join_pref iovar */
|
||||||
enum brcmf_join_pref_types {
|
enum brcmf_join_pref_types {
|
||||||
|
@ -124,6 +128,12 @@ enum brcmf_fil_p2p_if_types {
|
||||||
BRCMF_FIL_P2P_IF_DEV,
|
BRCMF_FIL_P2P_IF_DEV,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum brcmf_wowl_pattern_type {
|
||||||
|
BRCMF_WOWL_PATTERN_TYPE_BITMAP = 0,
|
||||||
|
BRCMF_WOWL_PATTERN_TYPE_ARP,
|
||||||
|
BRCMF_WOWL_PATTERN_TYPE_NA
|
||||||
|
};
|
||||||
|
|
||||||
struct brcmf_fil_p2p_if_le {
|
struct brcmf_fil_p2p_if_le {
|
||||||
u8 addr[ETH_ALEN];
|
u8 addr[ETH_ALEN];
|
||||||
__le16 type;
|
__le16 type;
|
||||||
|
@ -484,4 +494,29 @@ struct brcmf_rx_mgmt_data {
|
||||||
__be32 rate;
|
__be32 rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct brcmf_fil_wowl_pattern_le - wowl pattern configuration struct.
|
||||||
|
*
|
||||||
|
* @cmd: "add", "del" or "clr".
|
||||||
|
* @masksize: Size of the mask in #of bytes
|
||||||
|
* @offset: Pattern byte offset in packet
|
||||||
|
* @patternoffset: Offset of start of pattern. Starting from field masksize.
|
||||||
|
* @patternsize: Size of the pattern itself in #of bytes
|
||||||
|
* @id: id
|
||||||
|
* @reasonsize: Size of the wakeup reason code
|
||||||
|
* @type: Type of pattern (enum brcmf_wowl_pattern_type)
|
||||||
|
*/
|
||||||
|
struct brcmf_fil_wowl_pattern_le {
|
||||||
|
u8 cmd[4];
|
||||||
|
__le32 masksize;
|
||||||
|
__le32 offset;
|
||||||
|
__le32 patternoffset;
|
||||||
|
__le32 patternsize;
|
||||||
|
__le32 id;
|
||||||
|
__le32 reasonsize;
|
||||||
|
__le32 type;
|
||||||
|
/* u8 mask[] - Mask follows the structure above */
|
||||||
|
/* u8 pattern[] - Pattern follows the mask is at 'patternoffset' */
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* FWIL_TYPES_H_ */
|
#endif /* FWIL_TYPES_H_ */
|
||||||
|
|
|
@ -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)
|
static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
|
||||||
{
|
{
|
||||||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(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");
|
brcmf_dbg(TRACE, "Enter\n");
|
||||||
|
|
||||||
if (cfg->wowl_enabled) {
|
if (cfg->wowl_enabled) {
|
||||||
|
brcmf_configure_arp_offload(ifp, true);
|
||||||
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
|
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
|
||||||
cfg->pre_wowl_pmmode);
|
cfg->pre_wowl_pmmode);
|
||||||
brcmf_fil_iovar_data_set(ifp, "wowl_pattern", "clr", 4);
|
|
||||||
brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
|
brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
|
||||||
|
brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
|
||||||
cfg->wowl_enabled = false;
|
cfg->wowl_enabled = false;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2802,21 +2841,29 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
|
||||||
struct cfg80211_wowlan *wowl)
|
struct cfg80211_wowlan *wowl)
|
||||||
{
|
{
|
||||||
u32 wowl_config;
|
u32 wowl_config;
|
||||||
|
u32 i;
|
||||||
|
|
||||||
brcmf_dbg(TRACE, "Suspend, wowl config.\n");
|
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_get(ifp, BRCMF_C_GET_PM, &cfg->pre_wowl_pmmode);
|
||||||
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
|
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
|
||||||
|
|
||||||
wowl_config = 0;
|
wowl_config = 0;
|
||||||
if (wowl->disconnect)
|
if (wowl->disconnect)
|
||||||
wowl_config |= WL_WOWL_DIS | WL_WOWL_BCN | WL_WOWL_RETR;
|
wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_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)
|
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", wowl_config);
|
||||||
brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
|
brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
|
||||||
brcmf_bus_wowl_config(cfg->pub->bus_if, true);
|
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;
|
wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static const struct wiphy_wowlan_support brcmf_wowlan_support = {
|
static const struct wiphy_wowlan_support brcmf_wowlan_support = {
|
||||||
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
|
.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
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue