Commit d2b68e95 authored by Chin-Yen Lee's avatar Chin-Yen Lee Committed by Kalle Valo
Browse files

wifi: rtw89: add WoWLAN pattern match support



Pattern match is an option of WoWLAN to allow the device to be woken up
from suspend mode when receiving packets matched user-designed patterns.

The patterns are written into hardware via WoWLAN firmware in suspend
flow if users have set up them. If packets matched designed pattern are
received, WoWLAN firmware will send an interrupt and then wake up the
device.

Signed-off-by: default avatarChin-Yen Lee <timlee@realtek.com>
Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20221027052707.14605-8-pkshih@realtek.com
parent 19e28c7f
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -3489,9 +3489,27 @@ struct rtw89_phy_efuse_gain {
	s8 comp[RF_PATH_MAX][RTW89_SUBBAND_NR]; /* S(8, 0) */
};

#define RTW89_MAX_PATTERN_NUM             18
#define RTW89_MAX_PATTERN_MASK_SIZE       4
#define RTW89_MAX_PATTERN_SIZE            128

struct rtw89_wow_cam_info {
	bool r_w;
	u8 idx;
	u32 mask[RTW89_MAX_PATTERN_MASK_SIZE];
	u16 crc;
	bool negative_pattern_match;
	bool skip_mac_hdr;
	bool uc;
	bool mc;
	bool bc;
	bool valid;
};

struct rtw89_wow_param {
	struct ieee80211_vif *wow_vif;
	DECLARE_BITMAP(flags, RTW89_WOW_FLAG_NUM);
	struct rtw89_wow_cam_info patterns[RTW89_MAX_PATTERN_NUM];
	u8 pattern_cnt;
	struct list_head pkt_list;
};
+52 −0
Original line number Diff line number Diff line
@@ -3172,3 +3172,55 @@ int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev,

	return ret;
}

#define H2C_WOW_CAM_UPD_LEN 24
int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev,
			    struct rtw89_wow_cam_info *cam_info)
{
	struct sk_buff *skb;
	int ret;

	skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WOW_CAM_UPD_LEN);
	if (!skb) {
		rtw89_err(rtwdev, "failed to alloc skb for keep alive\n");
		return -ENOMEM;
	}

	skb_put(skb, H2C_WOW_CAM_UPD_LEN);

	RTW89_SET_WOW_CAM_UPD_R_W(skb->data, cam_info->r_w);
	RTW89_SET_WOW_CAM_UPD_IDX(skb->data, cam_info->idx);
	if (cam_info->valid) {
		RTW89_SET_WOW_CAM_UPD_WKFM1(skb->data, cam_info->mask[0]);
		RTW89_SET_WOW_CAM_UPD_WKFM2(skb->data, cam_info->mask[1]);
		RTW89_SET_WOW_CAM_UPD_WKFM3(skb->data, cam_info->mask[2]);
		RTW89_SET_WOW_CAM_UPD_WKFM4(skb->data, cam_info->mask[3]);
		RTW89_SET_WOW_CAM_UPD_CRC(skb->data, cam_info->crc);
		RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(skb->data,
							     cam_info->negative_pattern_match);
		RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(skb->data,
						   cam_info->skip_mac_hdr);
		RTW89_SET_WOW_CAM_UPD_UC(skb->data, cam_info->uc);
		RTW89_SET_WOW_CAM_UPD_MC(skb->data, cam_info->mc);
		RTW89_SET_WOW_CAM_UPD_BC(skb->data, cam_info->bc);
	}
	RTW89_SET_WOW_CAM_UPD_VALID(skb->data, cam_info->valid);

	rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
			      H2C_CAT_MAC,
			      H2C_CL_MAC_WOW,
			      H2C_FUNC_WOW_CAM_UPD, 0, 1,
			      H2C_WOW_CAM_UPD_LEN);

	ret = rtw89_h2c_tx(rtwdev, skb, false);
	if (ret) {
		rtw89_err(rtwdev, "failed to send h2c\n");
		goto fail;
	}

	return 0;
fail:
	dev_kfree_skb_any(skb);

	return ret;
}
+67 −0
Original line number Diff line number Diff line
@@ -2033,6 +2033,71 @@ static inline void RTW89_SET_WOW_WAKEUP_CTRL_MAC_ID(void *h2c, u32 val)
	le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24));
}

static inline void RTW89_SET_WOW_CAM_UPD_R_W(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c, val, BIT(0));
}

static inline void RTW89_SET_WOW_CAM_UPD_IDX(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 1));
}

static inline void RTW89_SET_WOW_CAM_UPD_WKFM1(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c + 1, val, GENMASK(31, 0));
}

static inline void RTW89_SET_WOW_CAM_UPD_WKFM2(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c + 2, val, GENMASK(31, 0));
}

static inline void RTW89_SET_WOW_CAM_UPD_WKFM3(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c + 3, val, GENMASK(31, 0));
}

static inline void RTW89_SET_WOW_CAM_UPD_WKFM4(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c + 4, val, GENMASK(31, 0));
}

static inline void RTW89_SET_WOW_CAM_UPD_CRC(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c + 5, val, GENMASK(15, 0));
}

static inline void RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c + 5, val, BIT(22));
}

static inline void RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c + 5, val, BIT(23));
}

static inline void RTW89_SET_WOW_CAM_UPD_UC(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c + 5, val, BIT(24));
}

static inline void RTW89_SET_WOW_CAM_UPD_MC(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c + 5, val, BIT(25));
}

static inline void RTW89_SET_WOW_CAM_UPD_BC(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c + 5, val, BIT(26));
}

static inline void RTW89_SET_WOW_CAM_UPD_VALID(void *h2c, u32 val)
{
	le32p_replace_bits((__le32 *)h2c + 5, val, BIT(31));
}

enum rtw89_btc_btf_h2c_class {
	BTFC_SET = 0x10,
	BTFC_GET = 0x11,
@@ -3039,6 +3104,8 @@ int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev,
				 struct rtw89_vif *rtwvif, bool enable);

int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev,
			    struct rtw89_wow_cam_info *cam_info);
static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev)
{
	const struct rtw89_chip_info *chip = rtwdev->chip;
+3 −0
Original line number Diff line number Diff line
@@ -1993,6 +1993,9 @@ static void rtw8852a_query_ppdu(struct rtw89_dev *rtwdev,
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support rtw_wowlan_stub_8852a = {
	.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
	.n_patterns = RTW89_MAX_PATTERN_NUM,
	.pattern_max_len = RTW89_MAX_PATTERN_SIZE,
	.pattern_min_len = 1,
};
#endif

+3 −0
Original line number Diff line number Diff line
@@ -2799,6 +2799,9 @@ static int rtw8852c_mac_disable_bb_rf(struct rtw89_dev *rtwdev)
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support rtw_wowlan_stub_8852c = {
	.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
	.n_patterns = RTW89_MAX_PATTERN_NUM,
	.pattern_max_len = RTW89_MAX_PATTERN_SIZE,
	.pattern_min_len = 1,
};
#endif

Loading