1 /* 2 * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 /** 20 * DOC: Define API's for wow pattern addition and deletion in fwr 21 */ 22 23 #include "wlan_pmo_wow.h" 24 #include "wlan_pmo_tgt_api.h" 25 #include "wlan_pmo_main.h" 26 #include "wlan_pmo_obj_mgmt_public_struct.h" 27 #include <wlan_scan_ucfg_api.h> 28 #include "wlan_pmo_static_config.h" 29 #include "wlan_reg_services_api.h" 30 #include "cfg_nan_api.h" 31 #include "wlan_utility.h" 32 33 void pmo_set_wow_event_bitmap(WOW_WAKE_EVENT_TYPE event, 34 uint32_t wow_bitmap_size, 35 uint32_t *bitmask) 36 { 37 uint32_t bit_idx = 0, idx = 0; 38 39 if (!bitmask || wow_bitmap_size < PMO_WOW_MAX_EVENT_BM_LEN) { 40 pmo_err("wow bitmask length shorter than %d", 41 PMO_WOW_MAX_EVENT_BM_LEN); 42 return; 43 } 44 pmo_get_event_bitmap_idx(event, wow_bitmap_size, &bit_idx, &idx); 45 bitmask[idx] |= 1 << bit_idx; 46 } 47 48 QDF_STATUS pmo_core_del_wow_pattern(struct wlan_objmgr_vdev *vdev) 49 { 50 QDF_STATUS status; 51 uint8_t id; 52 uint8_t pattern_count; 53 struct pmo_vdev_priv_obj *vdev_ctx; 54 55 status = pmo_vdev_get_ref(vdev); 56 if (QDF_IS_STATUS_ERROR(status)) 57 goto out; 58 59 vdev_ctx = pmo_vdev_get_priv(vdev); 60 pattern_count = pmo_get_wow_default_ptrn(vdev_ctx); 61 /* clear all default patterns configured by pmo */ 62 for (id = 0; id < pattern_count; id++) 63 status = pmo_tgt_del_wow_pattern(vdev, id, false); 64 65 /* clear all user patterns configured by pmo */ 66 pattern_count = pmo_get_wow_user_ptrn(vdev_ctx); 67 for (id = 0; id < pattern_count; id++) 68 status = pmo_tgt_del_wow_pattern(vdev, id, true); 69 70 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 71 out: 72 return status; 73 } 74 75 QDF_STATUS pmo_core_add_wow_user_pattern(struct wlan_objmgr_vdev *vdev, 76 struct pmo_wow_add_pattern *ptrn) 77 { 78 QDF_STATUS status; 79 uint8_t id; 80 uint8_t bit_to_check, pos; 81 uint8_t new_mask[PMO_WOWL_BCAST_PATTERN_MAX_SIZE]; 82 struct pmo_vdev_priv_obj *vdev_ctx; 83 84 status = pmo_vdev_get_ref(vdev); 85 if (QDF_IS_STATUS_ERROR(status)) 86 goto out; 87 88 vdev_ctx = pmo_vdev_get_priv(vdev); 89 90 /* clear all default patterns configured by pmo */ 91 for (id = 0; id < pmo_get_wow_default_ptrn(vdev_ctx); id++) 92 pmo_tgt_del_wow_pattern(vdev, id, false); 93 94 pmo_set_wow_default_ptrn(vdev_ctx, 0); 95 96 pmo_debug("Add user passed wow pattern id %d vdev id %d", 97 ptrn->pattern_id, wlan_vdev_get_id(vdev)); 98 /* 99 * Convert received pattern mask value from bit representation 100 * to byte representation. 101 * 102 * For example, received value from umac, 103 * 104 * Mask value : A1 (equivalent binary is "1010 0001") 105 * Pattern value : 12:00:13:00:00:00:00:44 106 * 107 * The value which goes to FW after the conversion from this 108 * function (1 in mask value will become FF and 0 will 109 * become 00), 110 * 111 * Mask value : FF:00:FF:00:00:00:00:FF 112 * Pattern value : 12:00:13:00:00:00:00:44 113 */ 114 qdf_mem_zero(new_mask, sizeof(new_mask)); 115 for (pos = 0; pos < ptrn->pattern_size; pos++) { 116 bit_to_check = (PMO_NUM_BITS_IN_BYTE - 1) - 117 (pos % PMO_NUM_BITS_IN_BYTE); 118 bit_to_check = 0x1 << bit_to_check; 119 if (ptrn->pattern_mask[pos / PMO_NUM_BITS_IN_BYTE] & 120 bit_to_check) 121 new_mask[pos] = PMO_WOW_PTRN_MASK_VALID; 122 } 123 124 status = pmo_tgt_send_wow_patterns_to_fw(vdev, 125 ptrn->pattern_id, 126 ptrn->pattern, 127 ptrn->pattern_size, 128 ptrn->pattern_byte_offset, 129 new_mask, 130 ptrn->pattern_size, true); 131 if (status != QDF_STATUS_SUCCESS) 132 pmo_err("Failed to add wow pattern %d", ptrn->pattern_id); 133 134 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 135 out: 136 pmo_exit(); 137 138 return status; 139 } 140 141 QDF_STATUS pmo_core_del_wow_user_pattern(struct wlan_objmgr_vdev *vdev, 142 uint8_t pattern_id) 143 { 144 QDF_STATUS status; 145 struct pmo_vdev_priv_obj *vdev_ctx; 146 147 status = pmo_vdev_get_ref(vdev); 148 if (QDF_IS_STATUS_ERROR(status)) 149 goto out; 150 151 vdev_ctx = pmo_vdev_get_priv(vdev); 152 if (pmo_get_wow_user_ptrn(vdev_ctx) <= 0) { 153 pmo_err("No valid user pattern. Num user pattern %u", 154 pmo_get_wow_user_ptrn(vdev_ctx)); 155 status = QDF_STATUS_E_INVAL; 156 goto rel_ref; 157 } 158 159 pmo_debug("Delete user passed wow pattern id %d total user pattern %d", 160 pattern_id, pmo_get_wow_user_ptrn(vdev_ctx)); 161 162 pmo_tgt_del_wow_pattern(vdev, pattern_id, true); 163 164 /* configure default patterns once all user patterns are deleted */ 165 if (!pmo_get_wow_user_ptrn(vdev_ctx)) 166 pmo_register_wow_default_patterns(vdev); 167 rel_ref: 168 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 169 out: 170 pmo_exit(); 171 172 return status; 173 } 174 175 void pmo_core_enable_wakeup_event(struct wlan_objmgr_psoc *psoc, 176 uint32_t vdev_id, 177 WOW_WAKE_EVENT_TYPE wow_event) 178 { 179 struct wlan_objmgr_vdev *vdev; 180 uint32_t bitmap[PMO_WOW_MAX_EVENT_BM_LEN] = {0}; 181 182 pmo_enter(); 183 184 if (!psoc) { 185 pmo_err("psoc is null"); 186 goto out; 187 } 188 189 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); 190 if (!vdev) { 191 pmo_err("vdev is NULL"); 192 goto out; 193 } 194 195 pmo_set_wow_event_bitmap(wow_event, PMO_WOW_MAX_EVENT_BM_LEN, bitmap); 196 197 pmo_tgt_enable_wow_wakeup_event(vdev, bitmap); 198 199 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 200 201 out: 202 pmo_exit(); 203 } 204 205 void pmo_core_disable_wakeup_event(struct wlan_objmgr_psoc *psoc, 206 uint32_t vdev_id, 207 WOW_WAKE_EVENT_TYPE wow_event) 208 { 209 struct wlan_objmgr_vdev *vdev; 210 uint32_t bitmap[PMO_WOW_MAX_EVENT_BM_LEN] = {0}; 211 212 if (!psoc) { 213 pmo_err("psoc is null"); 214 return; 215 } 216 217 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); 218 if (!vdev) { 219 pmo_err("vdev is NULL"); 220 return; 221 } 222 223 pmo_set_wow_event_bitmap(wow_event, PMO_WOW_MAX_EVENT_BM_LEN, bitmap); 224 225 pmo_tgt_disable_wow_wakeup_event(vdev, bitmap); 226 227 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 228 } 229 230 /** 231 * pmo_is_beaconing_vdev_up(): check if a beaconning vdev is up 232 * @psoc: objmgr psoc handle 233 * 234 * Return TRUE if beaconning vdev is up 235 */ 236 static 237 bool pmo_is_beaconing_vdev_up(struct wlan_objmgr_psoc *psoc) 238 { 239 int vdev_id; 240 struct wlan_objmgr_vdev *vdev; 241 enum QDF_OPMODE vdev_opmode; 242 bool is_beaconing; 243 244 /* Iterate through VDEV list */ 245 for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { 246 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 247 WLAN_PMO_ID); 248 if (!vdev) 249 continue; 250 251 vdev_opmode = pmo_get_vdev_opmode(vdev); 252 is_beaconing = pmo_is_vdev_in_beaconning_mode(vdev_opmode) && 253 QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(vdev)); 254 255 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 256 257 if (is_beaconing) 258 return true; 259 } 260 261 return false; 262 } 263 264 /** 265 * pmo_support_wow_for_beaconing: wow query for beaconning 266 * @psoc: objmgr psoc handle 267 * 268 * Need to configure wow to enable beaconning offload when 269 * a beaconing vdev is up and beaonning offload is configured. 270 * 271 * Return: true if we need to enable wow for beaconning offload 272 */ 273 static 274 bool pmo_support_wow_for_beaconing(struct wlan_objmgr_psoc *psoc) 275 { 276 /* 277 * if (wmi_service_enabled(wma->wmi_handle, 278 * wmi_service_beacon_offload)) 279 */ 280 return pmo_is_beaconing_vdev_up(psoc); 281 } 282 283 bool pmo_core_is_wow_applicable(struct wlan_objmgr_psoc *psoc) 284 { 285 int vdev_id; 286 struct wlan_objmgr_vdev *vdev; 287 bool is_wow_applicable = false; 288 289 if (!psoc) { 290 pmo_err("psoc is null"); 291 return false; 292 } 293 294 if (pmo_support_wow_for_beaconing(psoc)) { 295 pmo_debug("one of vdev is in beaconning mode, enabling wow"); 296 return true; 297 } 298 299 if (wlan_reg_is_11d_scan_inprogress(psoc)) { 300 pmo_debug("11d scan is in progress, enabling wow"); 301 return true; 302 } 303 304 if (pmo_core_is_lpass_enabled(psoc)) { 305 pmo_info("lpass enabled, enabling wow"); 306 return true; 307 } 308 309 if (cfg_nan_get_enable(psoc)) { 310 pmo_debug("nan enabled, enabling wow"); 311 return true; 312 } 313 314 /* Iterate through VDEV list */ 315 for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { 316 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 317 WLAN_PMO_ID); 318 if (!vdev) 319 continue; 320 321 if (wlan_vdev_is_up(vdev) == QDF_STATUS_SUCCESS) { 322 pmo_debug("STA is connected, enabling wow"); 323 is_wow_applicable = true; 324 } else if (ucfg_scan_get_pno_in_progress(vdev)) { 325 pmo_debug("NLO is in progress, enabling wow"); 326 is_wow_applicable = true; 327 } else if (pmo_core_is_extscan_in_progress(vdev)) { 328 pmo_debug("EXT is in progress, enabling wow"); 329 is_wow_applicable = true; 330 } else if (pmo_core_is_p2plo_in_progress(vdev)) { 331 pmo_debug("P2P LO is in progress, enabling wow"); 332 is_wow_applicable = true; 333 } else if (pmo_core_get_vdev_op_mode(vdev) == QDF_NDI_MODE) { 334 pmo_debug("vdev %d is in NAN data mode, enabling wow", 335 vdev_id); 336 is_wow_applicable = true; 337 } 338 339 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 340 341 if (is_wow_applicable) 342 return true; 343 } 344 345 pmo_debug("All vdev are in disconnected state\n" 346 "and pno/extscan is not in progress, skipping wow"); 347 348 return false; 349 } 350 351 void pmo_set_sta_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmap_size) 352 { 353 354 pmo_set_wow_event_bitmap(WOW_CSA_IE_EVENT, 355 wow_bitmap_size, 356 bitmask); 357 pmo_set_wow_event_bitmap(WOW_CLIENT_KICKOUT_EVENT, 358 wow_bitmap_size, 359 bitmask); 360 pmo_set_wow_event_bitmap(WOW_PATTERN_MATCH_EVENT, 361 wow_bitmap_size, 362 bitmask); 363 pmo_set_wow_event_bitmap(WOW_DEAUTH_RECVD_EVENT, 364 wow_bitmap_size, 365 bitmask); 366 pmo_set_wow_event_bitmap(WOW_DISASSOC_RECVD_EVENT, 367 wow_bitmap_size, 368 bitmask); 369 pmo_set_wow_event_bitmap(WOW_BMISS_EVENT, 370 wow_bitmap_size, 371 bitmask); 372 pmo_set_wow_event_bitmap(WOW_GTK_ERR_EVENT, 373 wow_bitmap_size, 374 bitmask); 375 pmo_set_wow_event_bitmap(WOW_BETTER_AP_EVENT, 376 wow_bitmap_size, 377 bitmask); 378 pmo_set_wow_event_bitmap(WOW_HTT_EVENT, 379 wow_bitmap_size, 380 bitmask); 381 pmo_set_wow_event_bitmap(WOW_RA_MATCH_EVENT, 382 wow_bitmap_size, 383 bitmask); 384 pmo_set_wow_event_bitmap(WOW_NLO_DETECTED_EVENT, 385 wow_bitmap_size, 386 bitmask); 387 pmo_set_wow_event_bitmap(WOW_EXTSCAN_EVENT, 388 wow_bitmap_size, 389 bitmask); 390 pmo_set_wow_event_bitmap(WOW_OEM_RESPONSE_EVENT, 391 wow_bitmap_size, 392 bitmask); 393 pmo_set_wow_event_bitmap(WOW_TDLS_CONN_TRACKER_EVENT, 394 wow_bitmap_size, 395 bitmask); 396 pmo_set_wow_event_bitmap(WOW_11D_SCAN_EVENT, 397 wow_bitmap_size, 398 bitmask); 399 pmo_set_wow_event_bitmap(WOW_NLO_SCAN_COMPLETE_EVENT, 400 wow_bitmap_size, 401 bitmask); 402 /* 403 * WPA3 roaming offloads SAE authentication to wpa_supplicant 404 * Firmware will send WMI_ROAM_PREAUTH_START_EVENTID 405 */ 406 pmo_set_wow_event_bitmap(WOW_ROAM_PREAUTH_START_EVENT, 407 wow_bitmap_size, 408 bitmask); 409 pmo_set_wow_event_bitmap(WOW_ROAM_PMKID_REQUEST_EVENT, 410 wow_bitmap_size, 411 bitmask); 412 pmo_set_wow_event_bitmap(WOW_VDEV_DISCONNECT_EVENT, 413 wow_bitmap_size, 414 bitmask); 415 416 pmo_set_wow_event_bitmap(WOW_TWT_EVENT, 417 wow_bitmap_size, 418 bitmask); 419 420 pmo_set_wow_event_bitmap(WOW_DCS_INTERFERENCE_DET, 421 wow_bitmap_size, 422 bitmask); 423 424 pmo_set_wow_event_bitmap(WOW_RTT_11AZ_EVENT, 425 wow_bitmap_size, bitmask); 426 } 427 428 void pmo_set_sap_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmap_size) 429 { 430 pmo_set_wow_event_bitmap(WOW_CLIENT_KICKOUT_EVENT, 431 wow_bitmap_size, 432 bitmask); 433 pmo_set_wow_event_bitmap(WOW_PROBE_REQ_WPS_IE_EVENT, 434 wow_bitmap_size, 435 bitmask); 436 pmo_set_wow_event_bitmap(WOW_PATTERN_MATCH_EVENT, 437 wow_bitmap_size, 438 bitmask); 439 pmo_set_wow_event_bitmap(WOW_AUTH_REQ_EVENT, 440 wow_bitmap_size, 441 bitmask); 442 pmo_set_wow_event_bitmap(WOW_ASSOC_REQ_EVENT, 443 wow_bitmap_size, 444 bitmask); 445 pmo_set_wow_event_bitmap(WOW_DEAUTH_RECVD_EVENT, 446 wow_bitmap_size, 447 bitmask); 448 pmo_set_wow_event_bitmap(WOW_DISASSOC_RECVD_EVENT, 449 wow_bitmap_size, 450 bitmask); 451 pmo_set_wow_event_bitmap(WOW_HTT_EVENT, 452 wow_bitmap_size, 453 bitmask); 454 pmo_set_wow_event_bitmap(WOW_SAP_OBSS_DETECTION_EVENT, 455 wow_bitmap_size, 456 bitmask); 457 pmo_set_wow_event_bitmap(WOW_BSS_COLOR_COLLISION_DETECT_EVENT, 458 wow_bitmap_size, 459 bitmask); 460 pmo_set_wow_event_bitmap(WOW_DCS_INTERFERENCE_DET, 461 wow_bitmap_size, 462 bitmask); 463 pmo_set_wow_event_bitmap(WOW_RTT_11AZ_EVENT, 464 wow_bitmap_size, bitmask); 465 pmo_set_wow_event_bitmap(WOW_XGAP_EVENT, 466 wow_bitmap_size, bitmask); 467 } 468 469 uint8_t pmo_get_num_wow_filters(struct wlan_objmgr_psoc *psoc) 470 { 471 struct pmo_psoc_priv_obj *psoc_ctx; 472 bool apf = false; 473 bool pkt_filter = false; 474 475 pmo_psoc_with_ctx(psoc, psoc_ctx) { 476 apf = pmo_intersect_apf(psoc_ctx); 477 pkt_filter = pmo_intersect_packet_filter(psoc_ctx); 478 } 479 480 if (!apf && !pkt_filter) 481 return PMO_WOW_FILTERS_MAX; 482 483 return PMO_WOW_FILTERS_PKT_OR_APF; 484 } 485 486 #ifdef WLAN_FEATURE_NAN 487 void pmo_set_ndp_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmap_size) 488 { 489 /* wake up host when Nan Management Frame is received */ 490 pmo_set_wow_event_bitmap(WOW_NAN_DATA_EVENT, 491 wow_bitmap_size, 492 bitmask); 493 /* wake up host when NDP data packet is received */ 494 pmo_set_wow_event_bitmap(WOW_PATTERN_MATCH_EVENT, 495 wow_bitmap_size, 496 bitmask); 497 } 498 #endif 499