Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: Chin-Yen Lee <timlee@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20221027052707.14605-8-pkshih@realtek.com

authored by

Chin-Yen Lee and committed by
Kalle Valo
d2b68e95 19e28c7f

+381 -1
+18
drivers/net/wireless/realtek/rtw89/core.h
··· 3489 3489 s8 comp[RF_PATH_MAX][RTW89_SUBBAND_NR]; /* S(8, 0) */ 3490 3490 }; 3491 3491 3492 + #define RTW89_MAX_PATTERN_NUM 18 3493 + #define RTW89_MAX_PATTERN_MASK_SIZE 4 3494 + #define RTW89_MAX_PATTERN_SIZE 128 3495 + 3496 + struct rtw89_wow_cam_info { 3497 + bool r_w; 3498 + u8 idx; 3499 + u32 mask[RTW89_MAX_PATTERN_MASK_SIZE]; 3500 + u16 crc; 3501 + bool negative_pattern_match; 3502 + bool skip_mac_hdr; 3503 + bool uc; 3504 + bool mc; 3505 + bool bc; 3506 + bool valid; 3507 + }; 3508 + 3492 3509 struct rtw89_wow_param { 3493 3510 struct ieee80211_vif *wow_vif; 3494 3511 DECLARE_BITMAP(flags, RTW89_WOW_FLAG_NUM); 3512 + struct rtw89_wow_cam_info patterns[RTW89_MAX_PATTERN_NUM]; 3495 3513 u8 pattern_cnt; 3496 3514 struct list_head pkt_list; 3497 3515 };
+52
drivers/net/wireless/realtek/rtw89/fw.c
··· 3172 3172 3173 3173 return ret; 3174 3174 } 3175 + 3176 + #define H2C_WOW_CAM_UPD_LEN 24 3177 + int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, 3178 + struct rtw89_wow_cam_info *cam_info) 3179 + { 3180 + struct sk_buff *skb; 3181 + int ret; 3182 + 3183 + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WOW_CAM_UPD_LEN); 3184 + if (!skb) { 3185 + rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); 3186 + return -ENOMEM; 3187 + } 3188 + 3189 + skb_put(skb, H2C_WOW_CAM_UPD_LEN); 3190 + 3191 + RTW89_SET_WOW_CAM_UPD_R_W(skb->data, cam_info->r_w); 3192 + RTW89_SET_WOW_CAM_UPD_IDX(skb->data, cam_info->idx); 3193 + if (cam_info->valid) { 3194 + RTW89_SET_WOW_CAM_UPD_WKFM1(skb->data, cam_info->mask[0]); 3195 + RTW89_SET_WOW_CAM_UPD_WKFM2(skb->data, cam_info->mask[1]); 3196 + RTW89_SET_WOW_CAM_UPD_WKFM3(skb->data, cam_info->mask[2]); 3197 + RTW89_SET_WOW_CAM_UPD_WKFM4(skb->data, cam_info->mask[3]); 3198 + RTW89_SET_WOW_CAM_UPD_CRC(skb->data, cam_info->crc); 3199 + RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(skb->data, 3200 + cam_info->negative_pattern_match); 3201 + RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(skb->data, 3202 + cam_info->skip_mac_hdr); 3203 + RTW89_SET_WOW_CAM_UPD_UC(skb->data, cam_info->uc); 3204 + RTW89_SET_WOW_CAM_UPD_MC(skb->data, cam_info->mc); 3205 + RTW89_SET_WOW_CAM_UPD_BC(skb->data, cam_info->bc); 3206 + } 3207 + RTW89_SET_WOW_CAM_UPD_VALID(skb->data, cam_info->valid); 3208 + 3209 + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, 3210 + H2C_CAT_MAC, 3211 + H2C_CL_MAC_WOW, 3212 + H2C_FUNC_WOW_CAM_UPD, 0, 1, 3213 + H2C_WOW_CAM_UPD_LEN); 3214 + 3215 + ret = rtw89_h2c_tx(rtwdev, skb, false); 3216 + if (ret) { 3217 + rtw89_err(rtwdev, "failed to send h2c\n"); 3218 + goto fail; 3219 + } 3220 + 3221 + return 0; 3222 + fail: 3223 + dev_kfree_skb_any(skb); 3224 + 3225 + return ret; 3226 + }
+67
drivers/net/wireless/realtek/rtw89/fw.h
··· 2033 2033 le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); 2034 2034 } 2035 2035 2036 + static inline void RTW89_SET_WOW_CAM_UPD_R_W(void *h2c, u32 val) 2037 + { 2038 + le32p_replace_bits((__le32 *)h2c, val, BIT(0)); 2039 + } 2040 + 2041 + static inline void RTW89_SET_WOW_CAM_UPD_IDX(void *h2c, u32 val) 2042 + { 2043 + le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 1)); 2044 + } 2045 + 2046 + static inline void RTW89_SET_WOW_CAM_UPD_WKFM1(void *h2c, u32 val) 2047 + { 2048 + le32p_replace_bits((__le32 *)h2c + 1, val, GENMASK(31, 0)); 2049 + } 2050 + 2051 + static inline void RTW89_SET_WOW_CAM_UPD_WKFM2(void *h2c, u32 val) 2052 + { 2053 + le32p_replace_bits((__le32 *)h2c + 2, val, GENMASK(31, 0)); 2054 + } 2055 + 2056 + static inline void RTW89_SET_WOW_CAM_UPD_WKFM3(void *h2c, u32 val) 2057 + { 2058 + le32p_replace_bits((__le32 *)h2c + 3, val, GENMASK(31, 0)); 2059 + } 2060 + 2061 + static inline void RTW89_SET_WOW_CAM_UPD_WKFM4(void *h2c, u32 val) 2062 + { 2063 + le32p_replace_bits((__le32 *)h2c + 4, val, GENMASK(31, 0)); 2064 + } 2065 + 2066 + static inline void RTW89_SET_WOW_CAM_UPD_CRC(void *h2c, u32 val) 2067 + { 2068 + le32p_replace_bits((__le32 *)h2c + 5, val, GENMASK(15, 0)); 2069 + } 2070 + 2071 + static inline void RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(void *h2c, u32 val) 2072 + { 2073 + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(22)); 2074 + } 2075 + 2076 + static inline void RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(void *h2c, u32 val) 2077 + { 2078 + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(23)); 2079 + } 2080 + 2081 + static inline void RTW89_SET_WOW_CAM_UPD_UC(void *h2c, u32 val) 2082 + { 2083 + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(24)); 2084 + } 2085 + 2086 + static inline void RTW89_SET_WOW_CAM_UPD_MC(void *h2c, u32 val) 2087 + { 2088 + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(25)); 2089 + } 2090 + 2091 + static inline void RTW89_SET_WOW_CAM_UPD_BC(void *h2c, u32 val) 2092 + { 2093 + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(26)); 2094 + } 2095 + 2096 + static inline void RTW89_SET_WOW_CAM_UPD_VALID(void *h2c, u32 val) 2097 + { 2098 + le32p_replace_bits((__le32 *)h2c + 5, val, BIT(31)); 2099 + } 2100 + 2036 2101 enum rtw89_btc_btf_h2c_class { 2037 2102 BTFC_SET = 0x10, 2038 2103 BTFC_GET = 0x11, ··· 3104 3039 int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, 3105 3040 struct rtw89_vif *rtwvif, bool enable); 3106 3041 3042 + int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, 3043 + struct rtw89_wow_cam_info *cam_info); 3107 3044 static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev) 3108 3045 { 3109 3046 const struct rtw89_chip_info *chip = rtwdev->chip;
+3
drivers/net/wireless/realtek/rtw89/rtw8852a.c
··· 1993 1993 #ifdef CONFIG_PM 1994 1994 static const struct wiphy_wowlan_support rtw_wowlan_stub_8852a = { 1995 1995 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, 1996 + .n_patterns = RTW89_MAX_PATTERN_NUM, 1997 + .pattern_max_len = RTW89_MAX_PATTERN_SIZE, 1998 + .pattern_min_len = 1, 1996 1999 }; 1997 2000 #endif 1998 2001
+3
drivers/net/wireless/realtek/rtw89/rtw8852c.c
··· 2799 2799 #ifdef CONFIG_PM 2800 2800 static const struct wiphy_wowlan_support rtw_wowlan_stub_8852c = { 2801 2801 .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, 2802 + .n_patterns = RTW89_MAX_PATTERN_NUM, 2803 + .pattern_max_len = RTW89_MAX_PATTERN_SIZE, 2804 + .pattern_min_len = 1, 2802 2805 }; 2803 2806 #endif 2804 2807
+11
drivers/net/wireless/realtek/rtw89/util.h
··· 44 44 return s32_div_u32_round_down(dividend + divisor / 2, divisor, NULL); 45 45 } 46 46 47 + static inline void ether_addr_copy_mask(u8 *dst, const u8 *src, u8 mask) 48 + { 49 + int i; 50 + 51 + eth_zero_addr(dst); 52 + for (i = 0; i < ETH_ALEN; i++) { 53 + if (mask & BIT(i)) 54 + dst[i] = src[i]; 55 + } 56 + } 57 + 47 58 #endif
+227 -1
drivers/net/wireless/realtek/rtw89/wow.c
··· 162 162 } 163 163 } 164 164 165 + static u16 __rtw89_cal_crc16(u8 data, u16 crc) 166 + { 167 + u8 shift_in, data_bit; 168 + u8 crc_bit4, crc_bit11, crc_bit15; 169 + u16 crc_result; 170 + int index; 171 + 172 + for (index = 0; index < 8; index++) { 173 + crc_bit15 = crc & BIT(15) ? 1 : 0; 174 + data_bit = data & BIT(index) ? 1 : 0; 175 + shift_in = crc_bit15 ^ data_bit; 176 + 177 + crc_result = crc << 1; 178 + 179 + if (shift_in == 0) 180 + crc_result &= ~BIT(0); 181 + else 182 + crc_result |= BIT(0); 183 + 184 + crc_bit11 = (crc & BIT(11) ? 1 : 0) ^ shift_in; 185 + 186 + if (crc_bit11 == 0) 187 + crc_result &= ~BIT(12); 188 + else 189 + crc_result |= BIT(12); 190 + 191 + crc_bit4 = (crc & BIT(4) ? 1 : 0) ^ shift_in; 192 + 193 + if (crc_bit4 == 0) 194 + crc_result &= ~BIT(5); 195 + else 196 + crc_result |= BIT(5); 197 + 198 + crc = crc_result; 199 + } 200 + return crc; 201 + } 202 + 203 + static u16 rtw89_calc_crc(u8 *pdata, int length) 204 + { 205 + u16 crc = 0xffff; 206 + int i; 207 + 208 + for (i = 0; i < length; i++) 209 + crc = __rtw89_cal_crc16(pdata[i], crc); 210 + 211 + /* get 1' complement */ 212 + return ~crc; 213 + } 214 + 215 + static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif, 216 + struct rtw89_wow_cam_info *rtw_pattern, 217 + const u8 *pattern, u8 da_mask) 218 + { 219 + u8 da[ETH_ALEN]; 220 + 221 + ether_addr_copy_mask(da, pattern, da_mask); 222 + 223 + /* Each pattern is divided into different kinds by DA address 224 + * a. DA is broadcast address: set bc = 0; 225 + * b. DA is multicast address: set mc = 0 226 + * c. DA is unicast address same as dev's mac address: set uc = 0 227 + * d. DA is unmasked. Also called wildcard type: set uc = bc = mc = 0 228 + * e. Others is invalid type. 229 + */ 230 + 231 + if (is_broadcast_ether_addr(da)) 232 + rtw_pattern->bc = true; 233 + else if (is_multicast_ether_addr(da)) 234 + rtw_pattern->mc = true; 235 + else if (ether_addr_equal(da, rtwvif->mac_addr) && 236 + da_mask == GENMASK(5, 0)) 237 + rtw_pattern->uc = true; 238 + else if (!da_mask) /*da_mask == 0 mean wildcard*/ 239 + return 0; 240 + else 241 + return -EPERM; 242 + 243 + return 0; 244 + } 245 + 246 + static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev, 247 + struct rtw89_vif *rtwvif, 248 + const struct cfg80211_pkt_pattern *pkt_pattern, 249 + struct rtw89_wow_cam_info *rtw_pattern) 250 + { 251 + u8 mask_hw[RTW89_MAX_PATTERN_MASK_SIZE * 4] = {0}; 252 + u8 content[RTW89_MAX_PATTERN_SIZE] = {0}; 253 + const u8 *mask; 254 + const u8 *pattern; 255 + u8 mask_len; 256 + u16 count; 257 + u32 len; 258 + int i, ret; 259 + 260 + pattern = pkt_pattern->pattern; 261 + len = pkt_pattern->pattern_len; 262 + mask = pkt_pattern->mask; 263 + mask_len = DIV_ROUND_UP(len, 8); 264 + memset(rtw_pattern, 0, sizeof(*rtw_pattern)); 265 + 266 + ret = rtw89_wow_pattern_get_type(rtwvif, rtw_pattern, pattern, 267 + mask[0] & GENMASK(5, 0)); 268 + if (ret) 269 + return ret; 270 + 271 + /* translate mask from os to mask for hw 272 + * pattern from OS uses 'ethenet frame', like this: 273 + * | 6 | 6 | 2 | 20 | Variable | 4 | 274 + * |--------+--------+------+-----------+------------+-----| 275 + * | 802.3 Mac Header | IP Header | TCP Packet | FCS | 276 + * | DA | SA | Type | 277 + * 278 + * BUT, packet catched by our HW is in '802.11 frame', begin from LLC 279 + * | 24 or 30 | 6 | 2 | 20 | Variable | 4 | 280 + * |-------------------+--------+------+-----------+------------+-----| 281 + * | 802.11 MAC Header | LLC | IP Header | TCP Packet | FCS | 282 + * | Others | Tpye | 283 + * 284 + * Therefore, we need translate mask_from_OS to mask_to_hw. 285 + * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0, 286 + * because new mask[0~5] means 'SA', but our HW packet begins from LLC, 287 + * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match. 288 + */ 289 + 290 + /* Shift 6 bits */ 291 + for (i = 0; i < mask_len - 1; i++) { 292 + mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6)) | 293 + u8_get_bits(mask[i + 1], GENMASK(5, 0)) << 2; 294 + } 295 + mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6)); 296 + 297 + /* Set bit 0-5 to zero */ 298 + mask_hw[0] &= ~GENMASK(5, 0); 299 + 300 + memcpy(rtw_pattern->mask, mask_hw, sizeof(rtw_pattern->mask)); 301 + 302 + /* To get the wake up pattern from the mask. 303 + * We do not count first 12 bits which means 304 + * DA[6] and SA[6] in the pattern to match HW design. 305 + */ 306 + count = 0; 307 + for (i = 12; i < len; i++) { 308 + if ((mask[i / 8] >> (i % 8)) & 0x01) { 309 + content[count] = pattern[i]; 310 + count++; 311 + } 312 + } 313 + 314 + rtw_pattern->crc = rtw89_calc_crc(content, count); 315 + 316 + return 0; 317 + } 318 + 319 + static int rtw89_wow_parse_patterns(struct rtw89_dev *rtwdev, 320 + struct rtw89_vif *rtwvif, 321 + struct cfg80211_wowlan *wowlan) 322 + { 323 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 324 + struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns; 325 + int i; 326 + int ret; 327 + 328 + if (!wowlan->n_patterns || !wowlan->patterns) 329 + return 0; 330 + 331 + for (i = 0; i < wowlan->n_patterns; i++) { 332 + rtw_pattern = &rtw_wow->patterns[i]; 333 + ret = rtw89_wow_pattern_generate(rtwdev, rtwvif, 334 + &wowlan->patterns[i], 335 + rtw_pattern); 336 + if (ret) { 337 + rtw89_err(rtwdev, "failed to generate pattern(%d)\n", i); 338 + rtw_wow->pattern_cnt = 0; 339 + return ret; 340 + } 341 + 342 + rtw_pattern->r_w = true; 343 + rtw_pattern->idx = i; 344 + rtw_pattern->negative_pattern_match = false; 345 + rtw_pattern->skip_mac_hdr = true; 346 + rtw_pattern->valid = true; 347 + } 348 + rtw_wow->pattern_cnt = wowlan->n_patterns; 349 + 350 + return 0; 351 + } 352 + 353 + static void rtw89_wow_pattern_clear_cam(struct rtw89_dev *rtwdev) 354 + { 355 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 356 + struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns; 357 + int i = 0; 358 + 359 + for (i = 0; i < rtw_wow->pattern_cnt; i++) { 360 + rtw_pattern = &rtw_wow->patterns[i]; 361 + rtw_pattern->valid = false; 362 + rtw89_fw_wow_cam_update(rtwdev, rtw_pattern); 363 + } 364 + } 365 + 366 + static void rtw89_wow_pattern_write(struct rtw89_dev *rtwdev) 367 + { 368 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 369 + struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns; 370 + int i; 371 + 372 + for (i = 0; i < rtw_wow->pattern_cnt; i++) 373 + rtw89_fw_wow_cam_update(rtwdev, rtw_pattern + i); 374 + } 375 + 376 + static void rtw89_wow_pattern_clear(struct rtw89_dev *rtwdev) 377 + { 378 + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 379 + 380 + rtw89_wow_pattern_clear_cam(rtwdev); 381 + 382 + rtw_wow->pattern_cnt = 0; 383 + memset(rtw_wow->patterns, 0, sizeof(rtw_wow->patterns)); 384 + } 385 + 165 386 static void rtw89_wow_clear_wakeups(struct rtw89_dev *rtwdev) 166 387 { 167 388 struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ··· 409 188 if (!rtw_wow->wow_vif) 410 189 return -EPERM; 411 190 412 - return 0; 191 + rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; 192 + return rtw89_wow_parse_patterns(rtwdev, rtwvif, wowlan); 413 193 } 414 194 415 195 static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow) ··· 664 442 struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; 665 443 int ret; 666 444 445 + rtw89_wow_pattern_write(rtwdev); 446 + 667 447 ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, true); 668 448 if (ret) { 669 449 rtw89_err(rtwdev, "wow: failed to enable keep alive\n"); ··· 699 475 struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 700 476 struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; 701 477 int ret; 478 + 479 + rtw89_wow_pattern_clear(rtwdev); 702 480 703 481 ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, false); 704 482 if (ret) {