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 
pmo_set_wow_event_bitmap(WOW_WAKE_EVENT_TYPE event,uint32_t wow_bitmap_size,uint32_t * bitmask)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 
pmo_core_del_wow_pattern(struct wlan_objmgr_vdev * vdev)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 
pmo_core_add_wow_user_pattern(struct wlan_objmgr_vdev * vdev,struct pmo_wow_add_pattern * ptrn)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 
pmo_core_del_wow_user_pattern(struct wlan_objmgr_vdev * vdev,uint8_t pattern_id)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 
pmo_core_enable_wakeup_event(struct wlan_objmgr_psoc * psoc,uint32_t vdev_id,WOW_WAKE_EVENT_TYPE wow_event)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 
pmo_core_disable_wakeup_event(struct wlan_objmgr_psoc * psoc,uint32_t vdev_id,WOW_WAKE_EVENT_TYPE wow_event)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
pmo_is_beaconing_vdev_up(struct wlan_objmgr_psoc * psoc)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
pmo_support_wow_for_beaconing(struct wlan_objmgr_psoc * psoc)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 
pmo_core_is_wow_applicable(struct wlan_objmgr_psoc * psoc)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 
pmo_set_sta_wow_bitmask(uint32_t * bitmask,uint32_t wow_bitmap_size)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 
pmo_set_sap_wow_bitmask(uint32_t * bitmask,uint32_t wow_bitmap_size)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 
pmo_get_num_wow_filters(struct wlan_objmgr_psoc * psoc)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
pmo_set_ndp_wow_bitmask(uint32_t * bitmask,uint32_t wow_bitmap_size)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