1 /*
2  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2024 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 /**
21  * DOC: wlan_hdd_power.c
22  *
23  * WLAN power management functions
24  *
25  */
26 
27 /* Include files */
28 
29 #include <linux/pm.h>
30 #include <linux/wait.h>
31 #include <linux/cpu.h>
32 #include "osif_sync.h"
33 #include <wlan_hdd_includes.h>
34 #if defined(CONFIG_HAS_WAKELOCK)
35 #include <linux/wakelock.h>
36 #endif
37 #include "qdf_types.h"
38 #include "sme_api.h"
39 #include <cds_api.h>
40 #include <cds_sched.h>
41 #include <mac_init_api.h>
42 #include <wlan_qct_sys.h>
43 #include <wlan_hdd_main.h>
44 #include <wlan_hdd_assoc.h>
45 #include <wlan_nlink_srv.h>
46 #include <wlan_hdd_misc.h>
47 #include <wlan_hdd_power.h>
48 #include <wlan_hdd_host_offload.h>
49 #include <dbglog_host.h>
50 #include <wlan_hdd_trace.h>
51 #include <wlan_hdd_p2p.h>
52 
53 #include <linux/semaphore.h>
54 #include <wlan_hdd_hostapd.h>
55 
56 #include <linux/inetdevice.h>
57 #include <wlan_hdd_cfg.h>
58 #include <wlan_hdd_scan.h>
59 #include <wlan_hdd_stats.h>
60 #include <wlan_hdd_cfg80211.h>
61 #include <net/addrconf.h>
62 #include <wlan_hdd_lpass.h>
63 
64 #include <wma_types.h>
65 #include <ol_txrx_osif_api.h>
66 #include <ol_defines.h>
67 #include "hif.h"
68 #include "hif_unit_test_suspend.h"
69 #include "sme_power_save_api.h"
70 #include "wlan_policy_mgr_api.h"
71 #include "cdp_txrx_flow_ctrl_v2.h"
72 #include "pld_common.h"
73 #include "wlan_hdd_driver_ops.h"
74 #include <wlan_logging_sock_svc.h>
75 #include "scheduler_api.h"
76 #include "cds_utils.h"
77 #include "wlan_hdd_packet_filter_api.h"
78 #include "wlan_cfg80211_scan.h"
79 #include "wlan_ipa_ucfg_api.h"
80 #include <wlan_cfg80211_mc_cp_stats.h>
81 #include "wlan_p2p_ucfg_api.h"
82 #include "wlan_mlme_ucfg_api.h"
83 #include "wlan_osif_request_manager.h"
84 #include <wlan_hdd_sar_limits.h>
85 #include "wlan_pkt_capture_ucfg_api.h"
86 #include "wlan_hdd_thermal.h"
87 #include "wlan_hdd_object_manager.h"
88 #include <linux/igmp.h>
89 #include "qdf_types.h"
90 #include <linux/cpuidle.h>
91 #include <cdp_txrx_ctrl.h>
92 #include <wlan_cp_stats_mc_ucfg_api.h>
93 #include "wlan_dp_ucfg_api.h"
94 
95 /* Preprocessor definitions and constants */
96 #ifdef QCA_WIFI_EMULATION
97 #define HDD_SSR_BRING_UP_TIME 3000000
98 #else
99 #define HDD_SSR_BRING_UP_TIME 30000
100 #endif
101 
102 /* Type declarations */
103 
104 #ifdef FEATURE_WLAN_DIAG_SUPPORT
hdd_wlan_suspend_resume_event(uint8_t state)105 void hdd_wlan_suspend_resume_event(uint8_t state)
106 {
107 	WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend);
108 	qdf_mem_zero(&suspend_state, sizeof(suspend_state));
109 
110 	suspend_state.state = state;
111 	WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
112 }
113 
114 /**
115  * hdd_wlan_offload_event() - send offloads event
116  * @type: offload type
117  * @state: enabled or disabled
118  *
119  * This Function send offloads enable/disable diag event
120  *
121  * Return: void.
122  */
123 
hdd_wlan_offload_event(uint8_t type,uint8_t state)124 void hdd_wlan_offload_event(uint8_t type, uint8_t state)
125 {
126 	WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req);
127 	qdf_mem_zero(&host_offload, sizeof(host_offload));
128 
129 	host_offload.offload_type = type;
130 	host_offload.state = state;
131 
132 	WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ);
133 }
134 #endif
135 
136 #ifdef WLAN_DP_LEGACY_OL_RX_THREAD
137 
138 /* timeout in msec to wait for RX_THREAD to suspend */
139 #define HDD_RXTHREAD_SUSPEND_TIMEOUT 200
140 
wlan_hdd_rx_thread_resume(struct hdd_context * hdd_ctx)141 void wlan_hdd_rx_thread_resume(struct hdd_context *hdd_ctx)
142 {
143 	if (hdd_ctx->is_ol_rx_thread_suspended) {
144 		cds_resume_rx_thread();
145 		hdd_ctx->is_ol_rx_thread_suspended = false;
146 	}
147 }
148 
wlan_hdd_rx_thread_suspend(struct hdd_context * hdd_ctx)149 int wlan_hdd_rx_thread_suspend(struct hdd_context *hdd_ctx)
150 {
151 	p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
152 	int rc;
153 
154 	if (!cds_sched_context)
155 		return 0;
156 
157 	/* Suspend tlshim rx thread */
158 	set_bit(RX_SUSPEND_EVENT, &cds_sched_context->ol_rx_event_flag);
159 	wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue);
160 	rc = wait_for_completion_timeout(&cds_sched_context->
161 					 ol_suspend_rx_event,
162 					 msecs_to_jiffies
163 					 (HDD_RXTHREAD_SUSPEND_TIMEOUT)
164 					);
165 	if (!rc) {
166 		clear_bit(RX_SUSPEND_EVENT,
167 			  &cds_sched_context->ol_rx_event_flag);
168 		hdd_err("Failed to stop tl_shim rx thread");
169 		return -EINVAL;
170 	}
171 	hdd_ctx->is_ol_rx_thread_suspended = true;
172 
173 	return 0;
174 }
175 #endif /* WLAN_DP_LEGACY_OL_RX_THREAD */
176 
177 /**
178  * hdd_enable_gtk_offload() - enable GTK offload
179  * @vdev: VDEV objmgr pointer
180  *
181  * Central function to enable GTK offload.
182  *
183  * Return: nothing
184  */
hdd_enable_gtk_offload(struct wlan_objmgr_vdev * vdev)185 static void hdd_enable_gtk_offload(struct wlan_objmgr_vdev *vdev)
186 {
187 	QDF_STATUS status;
188 
189 	status = ucfg_pmo_enable_gtk_offload_in_fwr(vdev);
190 	if (status != QDF_STATUS_SUCCESS)
191 		hdd_debug("Failed to enable gtk offload");
192 }
193 
194 #ifdef WLAN_FEATURE_IGMP_OFFLOAD
195 /**
196  * hdd_send_igmp_offload_params() - enable igmp offload
197  * @adapter: pointer to the adapter
198  * @vdev: VDEV ojbmgr pointer
199  * @enable: enable/disable
200  *
201  * Return: nothing
202  */
203 static QDF_STATUS
hdd_send_igmp_offload_params(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,bool enable)204 hdd_send_igmp_offload_params(struct hdd_adapter *adapter,
205 			     struct wlan_objmgr_vdev *vdev, bool enable)
206 {
207 	struct in_device *in_dev = adapter->dev->ip_ptr;
208 	struct ip_mc_list *ip_list;
209 	struct pmo_igmp_offload_req *igmp_req = NULL;
210 	int count = 0;
211 	QDF_STATUS status;
212 
213 	if (!in_dev) {
214 		hdd_err("in_dev is NULL");
215 		return QDF_STATUS_E_FAILURE;
216 	}
217 
218 	ip_list = in_dev->mc_list;
219 	if (!ip_list) {
220 		hdd_debug("ip list empty");
221 		return QDF_STATUS_E_FAILURE;
222 	}
223 
224 	igmp_req = qdf_mem_malloc(sizeof(*igmp_req));
225 	if (!igmp_req)
226 		return QDF_STATUS_E_FAILURE;
227 
228 	while (ip_list && ip_list->multiaddr && enable &&
229 	       count < MAX_MC_IP_ADDR) {
230 		if (IGMP_QUERY_ADDRESS !=  ip_list->multiaddr) {
231 			igmp_req->grp_ip_address[count] = ip_list->multiaddr;
232 			count++;
233 		}
234 
235 		ip_list = ip_list->next;
236 	}
237 	igmp_req->enable = enable;
238 	igmp_req->num_grp_ip_address = count;
239 
240 	status = ucfg_pmo_enable_igmp_offload(vdev, igmp_req);
241 	if (status != QDF_STATUS_SUCCESS)
242 		hdd_debug("Failed to configure igmp offload");
243 
244 	qdf_mem_free(igmp_req);
245 	return status;
246 }
247 
248 /**
249  * hdd_enable_igmp_offload() - enable GTK offload
250  * @adapter: pointer to the adapter
251  * @vdev: VDEV objmgr pointer
252  *
253  * Enable IGMP offload in suspended case to save power
254  *
255  * Return: nothing
256  */
hdd_enable_igmp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev)257 static void hdd_enable_igmp_offload(struct hdd_adapter *adapter,
258 				    struct wlan_objmgr_vdev *vdev)
259 {
260 	QDF_STATUS status;
261 
262 	status = hdd_send_igmp_offload_params(adapter, vdev, true);
263 	if (status != QDF_STATUS_SUCCESS)
264 		hdd_debug("Failed to enable igmp offload");
265 }
266 
267 /**
268  * hdd_disable_igmp_offload() - disable GTK offload
269  * @adapter: pointer to the adapter
270  * @vdev: VDEV objmgr pointer
271  *
272  * Enable IGMP offload in suspended case to save power
273  *
274  * Return: nothing
275  */
hdd_disable_igmp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev)276 static void hdd_disable_igmp_offload(struct hdd_adapter *adapter,
277 				     struct wlan_objmgr_vdev *vdev)
278 {
279 	QDF_STATUS status;
280 
281 	status = hdd_send_igmp_offload_params(adapter, vdev, false);
282 	if (status != QDF_STATUS_SUCCESS)
283 		hdd_debug("Failed to disable igmp offload");
284 }
285 #else
hdd_enable_igmp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev)286 static inline void hdd_enable_igmp_offload(struct hdd_adapter *adapter,
287 					   struct wlan_objmgr_vdev *vdev)
288 {}
289 
290 static inline QDF_STATUS
hdd_send_igmp_offload_params(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,bool enable)291 hdd_send_igmp_offload_params(struct hdd_adapter *adapter,
292 			     struct wlan_objmgr_vdev *vdev, bool enable)
293 {
294 	return QDF_STATUS_SUCCESS;
295 }
296 
hdd_disable_igmp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev)297 static inline void hdd_disable_igmp_offload(struct hdd_adapter *adapter,
298 					    struct wlan_objmgr_vdev *vdev)
299 {}
300 #endif
301 
302 /**
303  * hdd_disable_gtk_offload() - disable GTK offload
304  * @adapter:   pointer to the adapter
305  * @vdev: VDEV objmgr pointer
306  *
307  * Central function to disable GTK offload.
308  *
309  * Return: nothing
310  */
hdd_disable_gtk_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev)311 static void hdd_disable_gtk_offload(struct hdd_adapter *adapter,
312 				    struct wlan_objmgr_vdev *vdev)
313 {
314 	struct pmo_gtk_rsp_req gtk_rsp_request;
315 	QDF_STATUS status;
316 
317 	/* ensure to get gtk rsp first before disable it*/
318 	gtk_rsp_request.callback = wlan_hdd_cfg80211_update_replay_counter_cb;
319 
320 	/* Passing as void* as PMO does not know legacy HDD adapter type */
321 	gtk_rsp_request.callback_context = (void *)adapter;
322 
323 	status = ucfg_pmo_get_gtk_rsp(vdev, &gtk_rsp_request);
324 	if (status != QDF_STATUS_SUCCESS) {
325 		hdd_err("Failed to send get gtk rsp status:%d", status);
326 		return;
327 	}
328 
329 	hdd_debug("send get_gtk_rsp successful");
330 	status = ucfg_pmo_disable_gtk_offload_in_fwr(vdev);
331 	if (status != QDF_STATUS_SUCCESS)
332 		hdd_info("Failed to disable gtk offload");
333 }
334 
335 #ifdef WLAN_NS_OFFLOAD
336 /**
337  * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function
338  * @net_dev: net_device whose IP address changed
339  * @event: event from kernel, NETDEV_UP or NETDEV_DOWN
340  *
341  * This is a callback function that is registered with the kernel via
342  * register_inet6addr_notifier() which allows the driver to be
343  * notified when there is an IPv6 address change.
344  *
345  * Return: None
346  */
__wlan_hdd_ipv6_changed(struct net_device * net_dev,unsigned long event)347 static void __wlan_hdd_ipv6_changed(struct net_device *net_dev,
348 				    unsigned long event)
349 {
350 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev);
351 	struct hdd_context *hdd_ctx;
352 	int errno;
353 
354 	hdd_enter_dev(net_dev);
355 
356 	errno = hdd_validate_adapter(adapter);
357 	if (errno || adapter->dev != net_dev)
358 		goto exit;
359 
360 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
361 	errno = wlan_hdd_validate_context(hdd_ctx);
362 	if (errno)
363 		goto exit;
364 
365 	/* Only need to be notified for ipv6_add_addr
366 	 * No need for ipv6_del_addr or addrconf_ifdown
367 	 */
368 	if (event == NETDEV_UP &&
369 	    (adapter->device_mode == QDF_STA_MODE ||
370 	     adapter->device_mode == QDF_P2P_CLIENT_MODE)) {
371 		hdd_debug("invoking sme_dhcp_done_ind");
372 		sme_dhcp_done_ind(hdd_ctx->mac_handle,
373 				  adapter->deflink->vdev_id);
374 		schedule_work(&adapter->ipv6_notifier_work);
375 	}
376 
377 exit:
378 	hdd_exit();
379 }
380 
wlan_hdd_ipv6_changed(struct notifier_block * nb,unsigned long data,void * context)381 int wlan_hdd_ipv6_changed(struct notifier_block *nb,
382 			  unsigned long data, void *context)
383 {
384 	struct inet6_ifaddr *ifa = context;
385 	struct net_device *net_dev = ifa->idev->dev;
386 	struct osif_vdev_sync *vdev_sync;
387 
388 	if (osif_vdev_sync_op_start(net_dev, &vdev_sync))
389 		return NOTIFY_DONE;
390 
391 	__wlan_hdd_ipv6_changed(net_dev, data);
392 
393 	osif_vdev_sync_op_stop(vdev_sync);
394 
395 	return NOTIFY_DONE;
396 }
397 
398 /**
399  * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses
400  * @idev: pointer to net device
401  * @ipv6_uc_addr: destination array to fill IPv6 addresses
402  * @ipv6addr_type: IPv6 Address type
403  * @scope_array: scope of ipv6 addr
404  * @count: number of IPv6 addresses
405  *
406  * This is the IPv6 utility function to populate unicast addresses.
407  *
408  * Return: 0 on success, error number otherwise.
409  */
hdd_fill_ipv6_uc_addr(struct inet6_dev * idev,uint8_t ipv6_uc_addr[][QDF_IPV6_ADDR_SIZE],uint8_t * ipv6addr_type,enum pmo_ns_addr_scope * scope_array,uint32_t * count)410 static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
411 				uint8_t ipv6_uc_addr[][QDF_IPV6_ADDR_SIZE],
412 				uint8_t *ipv6addr_type,
413 				enum pmo_ns_addr_scope *scope_array,
414 				uint32_t *count)
415 {
416 	struct inet6_ifaddr *ifa;
417 	struct list_head *p;
418 	uint32_t scope;
419 
420 	read_lock_bh(&idev->lock);
421 	list_for_each(p, &idev->addr_list) {
422 		if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
423 			read_unlock_bh(&idev->lock);
424 			return -EINVAL;
425 		}
426 		ifa = list_entry(p, struct inet6_ifaddr, if_list);
427 		if (ifa->flags & IFA_F_DADFAILED)
428 			continue;
429 		scope = ipv6_addr_src_scope(&ifa->addr);
430 		switch (scope) {
431 		case IPV6_ADDR_SCOPE_GLOBAL:
432 		case IPV6_ADDR_SCOPE_LINKLOCAL:
433 			qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
434 				sizeof(ifa->addr.s6_addr));
435 			ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE;
436 			scope_array[*count] = ucfg_pmo_ns_addr_scope(scope);
437 			hdd_debug("Index %d scope = %s UC-Address: %pI6",
438 				*count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
439 				"LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
440 			*count += 1;
441 			break;
442 		default:
443 			hdd_warn("The Scope %d is not supported", scope);
444 		}
445 	}
446 
447 	read_unlock_bh(&idev->lock);
448 	return 0;
449 }
450 
451 /**
452  * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses
453  * @idev: pointer to net device
454  * @ipv6_ac_addr: destination array to fill IPv6 addresses
455  * @ipv6addr_type: IPv6 Address type
456  * @scope_array: scope of ipv6 addr
457  * @count: number of IPv6 addresses
458  *
459  * This is the IPv6 utility function to populate anycast addresses.
460  *
461  * Return: 0 on success, error number otherwise.
462  */
hdd_fill_ipv6_ac_addr(struct inet6_dev * idev,uint8_t ipv6_ac_addr[][QDF_IPV6_ADDR_SIZE],uint8_t * ipv6addr_type,enum pmo_ns_addr_scope * scope_array,uint32_t * count)463 static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
464 				uint8_t ipv6_ac_addr[][QDF_IPV6_ADDR_SIZE],
465 				uint8_t *ipv6addr_type,
466 				enum pmo_ns_addr_scope *scope_array,
467 				uint32_t *count)
468 {
469 	struct ifacaddr6 *ifaca;
470 	uint32_t scope;
471 
472 	read_lock_bh(&idev->lock);
473 	for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
474 		if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
475 			read_unlock_bh(&idev->lock);
476 			return -EINVAL;
477 		}
478 		/* For anycast addr no DAD */
479 		scope = ipv6_addr_src_scope(&ifaca->aca_addr);
480 		switch (scope) {
481 		case IPV6_ADDR_SCOPE_GLOBAL:
482 		case IPV6_ADDR_SCOPE_LINKLOCAL:
483 			qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
484 				sizeof(ifaca->aca_addr));
485 			ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE;
486 			scope_array[*count] = ucfg_pmo_ns_addr_scope(scope);
487 			hdd_debug("Index %d scope = %s AC-Address: %pI6",
488 				*count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
489 				"LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
490 			*count += 1;
491 			break;
492 		default:
493 			hdd_warn("The Scope %d is not supported", scope);
494 		}
495 	}
496 
497 	read_unlock_bh(&idev->lock);
498 	return 0;
499 }
500 
hdd_enable_ns_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)501 void hdd_enable_ns_offload(struct hdd_adapter *adapter,
502 			   struct wlan_objmgr_vdev *vdev,
503 			   enum pmo_offload_trigger trigger)
504 {
505 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
506 	struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc;
507 	struct inet6_dev *in6_dev;
508 	struct pmo_ns_req *ns_req;
509 	QDF_STATUS status;
510 	int errno;
511 	uint8_t vdev_id;
512 
513 	hdd_enter();
514 
515 	if (!psoc) {
516 		hdd_err("psoc is NULL");
517 		goto out;
518 	}
519 
520 	in6_dev = __in6_dev_get(adapter->dev);
521 	if (!in6_dev) {
522 		hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
523 		goto out;
524 	}
525 
526 	ns_req = qdf_mem_malloc(sizeof(*ns_req));
527 	if (!ns_req)
528 		goto out;
529 
530 	vdev_id = wlan_vdev_get_id(vdev);
531 
532 	ns_req->psoc = psoc;
533 	ns_req->vdev_id = vdev_id;
534 	ns_req->trigger = trigger;
535 	ns_req->count = 0;
536 
537 	/* check if offload cache and send is required or not */
538 	status = ucfg_pmo_ns_offload_check(psoc, trigger, vdev_id);
539 	if (QDF_IS_STATUS_ERROR(status)) {
540 		hdd_debug("NS offload is not required");
541 		goto free_req;
542 	}
543 
544 	if (ucfg_pmo_get_arp_ns_offload_dynamic_disable(vdev)) {
545 		hdd_debug("Dynamic arp ns offload disabled");
546 		ucfg_pmo_flush_ns_offload_req(vdev);
547 		goto skip_cache_ns;
548 	}
549 
550 	/* Unicast Addresses */
551 	errno = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
552 				      ns_req->ipv6_addr_type, ns_req->scope,
553 				      &ns_req->count);
554 	if (errno) {
555 		hdd_disable_ns_offload(adapter, vdev, trigger);
556 		hdd_debug("Max supported addresses: disabling NS offload");
557 		goto free_req;
558 	}
559 
560 	/* Anycast Addresses */
561 	errno = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
562 				      ns_req->ipv6_addr_type, ns_req->scope,
563 				      &ns_req->count);
564 	if (errno) {
565 		hdd_disable_ns_offload(adapter, vdev, trigger);
566 		hdd_debug("Max supported addresses: disabling NS offload");
567 		goto free_req;
568 	}
569 
570 	/* cache ns request */
571 	status = ucfg_pmo_cache_ns_offload_req(ns_req);
572 	if (QDF_IS_STATUS_ERROR(status)) {
573 		hdd_debug("Failed to cache ns request; status:%d", status);
574 		goto free_req;
575 	}
576 
577 skip_cache_ns:
578 	/* enable ns request */
579 	status = ucfg_pmo_enable_ns_offload_in_fwr(vdev, trigger);
580 	if (QDF_IS_STATUS_ERROR(status)) {
581 		hdd_debug("Failed to enable ns offload; status:%d", status);
582 		goto free_req;
583 	}
584 
585 	hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
586 free_req:
587 	qdf_mem_free(ns_req);
588 
589 out:
590 	hdd_exit();
591 }
592 
hdd_disable_ns_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)593 void hdd_disable_ns_offload(struct hdd_adapter *adapter,
594 			    struct wlan_objmgr_vdev *vdev,
595 			    enum pmo_offload_trigger trigger)
596 {
597 	QDF_STATUS status;
598 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
599 
600 	hdd_enter();
601 
602 	status = ucfg_pmo_ns_offload_check(hdd_ctx->psoc, trigger,
603 					   wlan_vdev_get_id(vdev));
604 	if (status != QDF_STATUS_SUCCESS) {
605 		hdd_debug("Flushing of NS offload not required");
606 		goto out;
607 	}
608 
609 	status = ucfg_pmo_flush_ns_offload_req(vdev);
610 	if (status != QDF_STATUS_SUCCESS) {
611 		hdd_err("Failed to flush NS Offload");
612 		goto out;
613 	}
614 
615 	status = ucfg_pmo_disable_ns_offload_in_fwr(vdev, trigger);
616 	if (status != QDF_STATUS_SUCCESS)
617 		hdd_err("Failed to disable NS Offload");
618 	else
619 		hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD,
620 			SIR_OFFLOAD_DISABLE);
621 out:
622 	hdd_exit();
623 
624 }
625 
626 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
627 #ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
hdd_send_mlo_ps_to_fw(struct hdd_adapter * adapter)628 static void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter)
629 {
630 	struct wlan_hdd_link_info *link_info;
631 	mac_handle_t mac_handle;
632 
633 	if (!adapter) {
634 		hdd_err_rl("null hdd_adapter pointer");
635 		return;
636 	}
637 
638 	mac_handle = hdd_adapter_get_mac_handle(adapter);
639 
640 	if (!mac_handle) {
641 		hdd_err_rl("null mac_handle pointer");
642 		return;
643 	}
644 
645 	hdd_adapter_for_each_active_link_info(adapter, link_info)
646 		sme_ps_update(mac_handle, link_info->vdev_id);
647 }
648 #else
hdd_send_mlo_ps_to_fw(struct hdd_adapter * adapter)649 static void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter)
650 {
651 	int i;
652 	struct hdd_adapter *link_adapter;
653 	struct hdd_mlo_adapter_info *mlo_adapter_info;
654 	mac_handle_t mac_handle;
655 
656 	if (!adapter) {
657 		hdd_err_rl("null hdd_adapter pointer");
658 		return;
659 	}
660 
661 	mac_handle = hdd_adapter_get_mac_handle(adapter);
662 
663 	if (!mac_handle) {
664 		hdd_err_rl("null mac_handle pointer");
665 		return;
666 	}
667 
668 	mlo_adapter_info = &adapter->mlo_adapter_info;
669 	for (i = 0; i < WLAN_MAX_MLD; i++) {
670 		link_adapter = mlo_adapter_info->link_adapter[i];
671 		if (!link_adapter)
672 			continue;
673 		sme_ps_update(mac_handle, link_adapter->deflink->vdev_id);
674 	}
675 }
676 #endif
677 #else
hdd_send_mlo_ps_to_fw(struct hdd_adapter * adapter)678 static inline void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter)
679 {}
680 #endif
681 
hdd_send_ps_config_to_fw(struct hdd_adapter * adapter)682 void hdd_send_ps_config_to_fw(struct hdd_adapter *adapter)
683 {
684 	struct hdd_context *hdd_ctx;
685 	bool is_mlo_vdev;
686 
687 	if (hdd_validate_adapter(adapter))
688 		return;
689 
690 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
691 
692 	is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(adapter->deflink->vdev);
693 
694 	if (!is_mlo_vdev) {
695 		sme_ps_update(hdd_ctx->mac_handle, adapter->deflink->vdev_id);
696 		return;
697 	}
698 
699 	hdd_send_mlo_ps_to_fw(adapter);
700 }
701 
702 /**
703  * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function
704  * @adapter: adapter whose IP address changed
705  *
706  * This function performs the work initially triggered by a callback
707  * from the IPv6 netdev notifier.  Since this means there has been a
708  * change in IPv6 state for the interface, the NS offload is
709  * reconfigured.
710  *
711  * Return: None
712  */
__hdd_ipv6_notifier_work_queue(struct hdd_adapter * adapter)713 static void __hdd_ipv6_notifier_work_queue(struct hdd_adapter *adapter)
714 {
715 	struct hdd_context *hdd_ctx;
716 	int errno;
717 	struct wlan_objmgr_vdev *vdev;
718 
719 	hdd_enter();
720 
721 	errno = hdd_validate_adapter(adapter);
722 	if (errno)
723 		goto exit;
724 
725 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
726 	errno = wlan_hdd_validate_context(hdd_ctx);
727 	if (errno)
728 		goto exit;
729 
730 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID);
731 	if (!vdev)
732 		goto exit;
733 
734 	hdd_enable_ns_offload(adapter, vdev, pmo_ipv6_change_notify);
735 	hdd_enable_icmp_offload(adapter, vdev, pmo_ipv6_change_notify);
736 	hdd_send_ps_config_to_fw(adapter);
737 
738 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
739 exit:
740 	hdd_exit();
741 }
742 
hdd_ipv6_notifier_work_queue(struct work_struct * work)743 void hdd_ipv6_notifier_work_queue(struct work_struct *work)
744 {
745 	struct hdd_adapter *adapter = container_of(work, struct hdd_adapter,
746 						   ipv6_notifier_work);
747 	struct osif_vdev_sync *vdev_sync;
748 
749 	if (osif_vdev_sync_op_start(adapter->dev, &vdev_sync))
750 		return;
751 
752 	__hdd_ipv6_notifier_work_queue(adapter);
753 
754 	osif_vdev_sync_op_stop(vdev_sync);
755 }
756 #endif /* WLAN_NS_OFFLOAD */
757 
hdd_enable_hw_filter(struct wlan_objmgr_vdev * vdev)758 static void hdd_enable_hw_filter(struct wlan_objmgr_vdev *vdev)
759 {
760 	QDF_STATUS status;
761 
762 	hdd_enter();
763 
764 	status = ucfg_pmo_enable_hw_filter_in_fwr(vdev);
765 	if (status != QDF_STATUS_SUCCESS)
766 		hdd_info("Failed to enable hardware filter");
767 
768 	hdd_exit();
769 }
770 
hdd_disable_hw_filter(struct wlan_objmgr_vdev * vdev)771 static void hdd_disable_hw_filter(struct wlan_objmgr_vdev *vdev)
772 {
773 	QDF_STATUS status;
774 
775 	hdd_enter();
776 
777 	status = ucfg_pmo_disable_hw_filter_in_fwr(vdev);
778 	if (status != QDF_STATUS_SUCCESS)
779 		hdd_info("Failed to disable hardware filter");
780 
781 	hdd_exit();
782 }
783 
hdd_enable_action_frame_patterns(struct wlan_objmgr_vdev * vdev)784 static void hdd_enable_action_frame_patterns(struct wlan_objmgr_vdev *vdev)
785 {
786 	QDF_STATUS status;
787 
788 	hdd_enter();
789 
790 	status = ucfg_pmo_enable_action_frame_patterns(vdev,
791 						       QDF_SYSTEM_SUSPEND);
792 	if (QDF_IS_STATUS_ERROR(status))
793 		hdd_info("Failed to enable action frame patterns");
794 
795 	hdd_exit();
796 }
797 
hdd_disable_action_frame_patterns(struct wlan_objmgr_vdev * vdev)798 static void hdd_disable_action_frame_patterns(struct wlan_objmgr_vdev *vdev)
799 {
800 	QDF_STATUS status;
801 
802 	hdd_enter();
803 
804 	status = ucfg_pmo_disable_action_frame_patterns(vdev);
805 	if (QDF_IS_STATUS_ERROR(status))
806 		hdd_info("Failed to disable action frame patterns");
807 
808 	hdd_exit();
809 }
810 
hdd_enable_host_offloads(struct hdd_adapter * adapter,enum pmo_offload_trigger trigger)811 void hdd_enable_host_offloads(struct hdd_adapter *adapter,
812 	enum pmo_offload_trigger trigger)
813 {
814 	struct wlan_objmgr_vdev *vdev;
815 
816 	hdd_enter();
817 
818 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
819 					   WLAN_OSIF_POWER_ID);
820 	if (!vdev) {
821 		hdd_err("vdev is NULL");
822 		goto out;
823 	}
824 
825 	if (!ucfg_pmo_is_vdev_supports_offload(vdev)) {
826 		hdd_debug("offload is not supported on vdev opmode %d",
827 			  adapter->device_mode);
828 		goto put_vdev;
829 	}
830 
831 	if (!ucfg_pmo_is_vdev_connected(vdev)) {
832 		hdd_debug("offload is not supported on disconnected vdevs");
833 		goto put_vdev;
834 	}
835 
836 	hdd_debug("enable offloads");
837 	hdd_enable_gtk_offload(vdev);
838 	hdd_enable_arp_offload(adapter, vdev, trigger);
839 	hdd_enable_ns_offload(adapter, vdev, trigger);
840 	hdd_enable_mc_addr_filtering(adapter, trigger);
841 	if (adapter->device_mode == QDF_STA_MODE)
842 		hdd_enable_igmp_offload(adapter, vdev);
843 
844 	if (adapter->device_mode != QDF_NDI_MODE)
845 		hdd_enable_hw_filter(vdev);
846 	hdd_enable_action_frame_patterns(vdev);
847 put_vdev:
848 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
849 out:
850 	hdd_exit();
851 
852 }
853 
hdd_disable_host_offloads(struct hdd_adapter * adapter,enum pmo_offload_trigger trigger)854 void hdd_disable_host_offloads(struct hdd_adapter *adapter,
855 	enum pmo_offload_trigger trigger)
856 {
857 	struct wlan_objmgr_vdev *vdev;
858 
859 	hdd_enter();
860 
861 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
862 					   WLAN_OSIF_POWER_ID);
863 	if (!vdev) {
864 		hdd_err("vdev is NULL");
865 		goto out;
866 	}
867 
868 	if (!ucfg_pmo_is_vdev_supports_offload(vdev)) {
869 		hdd_info("offload is not supported on this vdev opmode: %d",
870 				adapter->device_mode);
871 			goto put_vdev;
872 	}
873 
874 	if (!ucfg_pmo_is_vdev_connected(vdev)) {
875 		hdd_info("vdev is not connected");
876 		goto put_vdev;
877 	}
878 
879 	hdd_debug("disable offloads");
880 	hdd_disable_gtk_offload(adapter, vdev);
881 	hdd_disable_arp_offload(adapter, vdev, trigger);
882 	hdd_disable_ns_offload(adapter, vdev, trigger);
883 	hdd_disable_mc_addr_filtering(adapter, trigger);
884 	if (adapter->device_mode == QDF_STA_MODE)
885 		hdd_disable_igmp_offload(adapter, vdev);
886 	if (adapter->device_mode != QDF_NDI_MODE)
887 		hdd_disable_hw_filter(vdev);
888 	hdd_disable_action_frame_patterns(vdev);
889 
890 put_vdev:
891 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
892 out:
893 	hdd_exit();
894 
895 }
896 
897 /**
898  * hdd_lookup_ifaddr() - Lookup interface address data by name
899  * @adapter: the adapter whose name should be searched for
900  *
901  * return in_ifaddr pointer on success, NULL for failure
902  */
hdd_lookup_ifaddr(struct hdd_adapter * adapter)903 static struct in_ifaddr *hdd_lookup_ifaddr(struct hdd_adapter *adapter)
904 {
905 	struct in_ifaddr *ifa;
906 	struct in_device *in_dev;
907 
908 	if (!adapter) {
909 		hdd_err("adapter is null");
910 		return NULL;
911 	}
912 
913 	in_dev = __in_dev_get_rtnl(adapter->dev);
914 	if (!in_dev) {
915 		hdd_err("Failed to get in_device");
916 		return NULL;
917 	}
918 
919 	/* lookup address data by interface name */
920 	for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
921 		if (!strcmp(adapter->dev->name, ifa->ifa_label))
922 			return ifa;
923 	}
924 
925 	return NULL;
926 }
927 
928 /**
929  * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address
930  * @adapter: the adapter whose IPv4 address is desired
931  * @ipv4_addr: the address of the array to copy the IPv4 address into
932  *
933  * return: zero for success; non-zero for failure
934  */
hdd_populate_ipv4_addr(struct hdd_adapter * adapter,uint8_t * ipv4_addr)935 static int hdd_populate_ipv4_addr(struct hdd_adapter *adapter,
936 				  uint8_t *ipv4_addr)
937 {
938 	struct in_ifaddr *ifa;
939 	int i;
940 
941 	if (!adapter) {
942 		hdd_err("adapter is null");
943 		return -EINVAL;
944 	}
945 
946 	if (!ipv4_addr) {
947 		hdd_err("ipv4_addr is null");
948 		return -EINVAL;
949 	}
950 
951 	ifa = hdd_lookup_ifaddr(adapter);
952 	if (!ifa || !ifa->ifa_local) {
953 		hdd_err("ipv4 address not found");
954 		return -EINVAL;
955 	}
956 
957 	/* convert u32 to byte array */
958 	for (i = 0; i < 4; i++)
959 		ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff;
960 
961 	return 0;
962 }
963 
hdd_set_grat_arp_keepalive(struct hdd_adapter * adapter)964 int hdd_set_grat_arp_keepalive(struct hdd_adapter *adapter)
965 {
966 	QDF_STATUS status;
967 	int exit_code;
968 	struct hdd_context *hdd_ctx;
969 	struct hdd_station_ctx *sta_ctx;
970 	struct keep_alive_req req = {
971 		.packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP,
972 		.dest_macaddr = QDF_MAC_ADDR_BCAST_INIT,
973 	};
974 
975 	if (!adapter) {
976 		hdd_err("adapter is null");
977 		return -EINVAL;
978 	}
979 
980 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
981 	if (!hdd_ctx) {
982 		hdd_err("hdd_ctx is null");
983 		return -EINVAL;
984 	}
985 
986 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
987 	if (!sta_ctx) {
988 		hdd_err("sta_ctx is null");
989 		return -EINVAL;
990 	}
991 
992 	exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr);
993 	if (exit_code) {
994 		hdd_err("Failed to populate ipv4 address");
995 		return exit_code;
996 	}
997 
998 	/* according to RFC5227, sender/target ip address should be the same */
999 	qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr,
1000 		     sizeof(req.destIpv4Addr));
1001 
1002 	qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssid);
1003 	ucfg_mlme_get_sta_keep_alive_period(hdd_ctx->psoc, &req.timePeriod);
1004 	req.sessionId = adapter->deflink->vdev_id;
1005 
1006 	hdd_debug("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u",
1007 		 req.hostIpv4Addr[0], req.hostIpv4Addr[1],
1008 		 req.hostIpv4Addr[2], req.hostIpv4Addr[3]);
1009 
1010 	status = sme_set_keep_alive(hdd_ctx->mac_handle, req.sessionId, &req);
1011 	if (QDF_IS_STATUS_ERROR(status)) {
1012 		hdd_err("Failed to set keepalive");
1013 		return qdf_status_to_os_return(status);
1014 	}
1015 
1016 	return 0;
1017 }
1018 
1019 /**
1020  * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function
1021  * @adapter: adapter whose IP address changed
1022  *
1023  * This function performs the work initially triggered by a callback
1024  * from the IPv4 netdev notifier.  Since this means there has been a
1025  * change in IPv4 state for the interface, the ARP offload is
1026  * reconfigured. Also, Updates the HLP IE info with IP address info
1027  * to fw if LFR3 is enabled
1028  *
1029  * Return: None
1030  */
__hdd_ipv4_notifier_work_queue(struct hdd_adapter * adapter)1031 static void __hdd_ipv4_notifier_work_queue(struct hdd_adapter *adapter)
1032 {
1033 	struct hdd_context *hdd_ctx;
1034 	int errno;
1035 	struct in_ifaddr *ifa;
1036 	enum station_keepalive_method val;
1037 	QDF_STATUS status;
1038 	struct wlan_objmgr_vdev *vdev;
1039 
1040 	hdd_enter();
1041 
1042 	errno = hdd_validate_adapter(adapter);
1043 	if (errno)
1044 		goto exit;
1045 
1046 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1047 	errno = wlan_hdd_validate_context(hdd_ctx);
1048 	if (errno)
1049 		goto exit;
1050 
1051 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID);
1052 	if (!vdev)
1053 		goto exit;
1054 
1055 	hdd_enable_arp_offload(adapter, vdev, pmo_ipv4_change_notify);
1056 	hdd_enable_icmp_offload(adapter, vdev, pmo_ipv4_change_notify);
1057 
1058 	status = ucfg_mlme_get_sta_keepalive_method(hdd_ctx->psoc, &val);
1059 	if (QDF_IS_STATUS_ERROR(status))
1060 		goto vdev_ref;
1061 
1062 	if (val == MLME_STA_KEEPALIVE_GRAT_ARP)
1063 		hdd_set_grat_arp_keepalive(adapter);
1064 
1065 	hdd_debug("FILS Roaming support: %d",
1066 		  hdd_ctx->is_fils_roaming_supported);
1067 
1068 	ifa = hdd_lookup_ifaddr(adapter);
1069 	if (ifa && hdd_ctx->is_fils_roaming_supported)
1070 		sme_send_hlp_ie_info(hdd_ctx->mac_handle,
1071 				     wlan_vdev_get_id(vdev),
1072 				     ifa->ifa_local);
1073 	hdd_send_ps_config_to_fw(adapter);
1074 
1075 vdev_ref:
1076 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1077 exit:
1078 	hdd_exit();
1079 }
1080 
hdd_ipv4_notifier_work_queue(struct work_struct * work)1081 void hdd_ipv4_notifier_work_queue(struct work_struct *work)
1082 {
1083 	struct hdd_adapter *adapter = container_of(work, struct hdd_adapter,
1084 						   ipv4_notifier_work);
1085 	struct osif_vdev_sync *vdev_sync;
1086 
1087 	if (osif_vdev_sync_op_start(adapter->dev, &vdev_sync))
1088 		return;
1089 
1090 	__hdd_ipv4_notifier_work_queue(adapter);
1091 
1092 	osif_vdev_sync_op_stop(vdev_sync);
1093 }
1094 
1095 /**
1096  * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function
1097  * @net_dev: the net_device whose IP address changed
1098  *
1099  * This is a callback function that is registered with the kernel via
1100  * register_inetaddr_notifier() which allows the driver to be
1101  * notified when there is an IPv4 address change.
1102  *
1103  * Return: None
1104  */
__wlan_hdd_ipv4_changed(struct net_device * net_dev)1105 static void __wlan_hdd_ipv4_changed(struct net_device *net_dev)
1106 {
1107 	struct in_ifaddr *ifa;
1108 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev);
1109 	struct hdd_context *hdd_ctx;
1110 	int errno;
1111 
1112 	hdd_enter_dev(net_dev);
1113 
1114 	errno = hdd_validate_adapter(adapter);
1115 	if (errno || adapter->dev != net_dev)
1116 		goto exit;
1117 
1118 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1119 	errno = wlan_hdd_validate_context(hdd_ctx);
1120 	if (errno)
1121 		goto exit;
1122 
1123 	if (adapter->device_mode == QDF_STA_MODE ||
1124 	    adapter->device_mode == QDF_P2P_CLIENT_MODE) {
1125 		hdd_debug("invoking sme_dhcp_done_ind");
1126 		sme_dhcp_done_ind(hdd_ctx->mac_handle,
1127 				  adapter->deflink->vdev_id);
1128 
1129 		if (!ucfg_pmo_is_arp_offload_enabled(hdd_ctx->psoc)) {
1130 			hdd_debug("Offload not enabled");
1131 			goto exit;
1132 		}
1133 
1134 		ifa = hdd_lookup_ifaddr(adapter);
1135 		if (ifa && ifa->ifa_local)
1136 			schedule_work(&adapter->ipv4_notifier_work);
1137 	}
1138 
1139 exit:
1140 	hdd_exit();
1141 }
1142 
wlan_hdd_ipv4_changed(struct notifier_block * nb,unsigned long data,void * context)1143 int wlan_hdd_ipv4_changed(struct notifier_block *nb,
1144 			  unsigned long data, void *context)
1145 {
1146 	struct in_ifaddr *ifa = context;
1147 	struct net_device *net_dev = ifa->ifa_dev->dev;
1148 	struct osif_vdev_sync *vdev_sync;
1149 
1150 	if (osif_vdev_sync_op_start(net_dev, &vdev_sync))
1151 		return NOTIFY_DONE;
1152 
1153 	__wlan_hdd_ipv4_changed(net_dev);
1154 
1155 	osif_vdev_sync_op_stop(vdev_sync);
1156 
1157 	return NOTIFY_DONE;
1158 }
1159 
1160 #ifdef FEATURE_RUNTIME_PM
1161 /* For CPU, the enter & exit latency of the deepest LPM mode(CXPC)
1162  * is about ~10ms. so long as required QoS latency is longer than 10ms,
1163  * CPU can enter CXPC mode.
1164  * The vote value is in microseconds.
1165  */
wlan_hdd_is_cpu_cxpc_allowed(struct hdd_context * hdd_ctx,unsigned long vote)1166 static bool wlan_hdd_is_cpu_cxpc_allowed(struct hdd_context *hdd_ctx,
1167 					 unsigned long vote)
1168 {
1169 	if (vote >= hdd_ctx->config->cpu_cxpc_threshold)
1170 		return true;
1171 	else
1172 		return false;
1173 }
1174 
wlan_hdd_pm_qos_notify(struct notifier_block * nb,unsigned long curr_val,void * context)1175 int wlan_hdd_pm_qos_notify(struct notifier_block *nb, unsigned long curr_val,
1176 			   void *context)
1177 {
1178 	struct hdd_context *hdd_ctx = container_of(nb, struct hdd_context,
1179 						   pm_qos_notifier);
1180 	void *hif_ctx;
1181 	bool is_any_sta_connected = false;
1182 
1183 	if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1184 		hdd_debug_rl("Driver Module closed; skipping pm qos notify");
1185 		return 0;
1186 	}
1187 
1188 	hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
1189 	if (!hif_ctx)
1190 		return -EINVAL;
1191 
1192 	is_any_sta_connected = hdd_is_any_sta_connected(hdd_ctx);
1193 
1194 	hdd_debug("PM QOS update: runtime_pm_prevented %d Current value: %ld, is_any_sta_connected %d",
1195 		  hdd_ctx->runtime_pm_prevented, curr_val,
1196 		  is_any_sta_connected);
1197 	qdf_spin_lock_irqsave(&hdd_ctx->pm_qos_lock);
1198 
1199 	if (!hdd_ctx->runtime_pm_prevented &&
1200 	    is_any_sta_connected &&
1201 	    !wlan_hdd_is_cpu_cxpc_allowed(hdd_ctx, curr_val)) {
1202 		hif_rtpm_get(HIF_RTPM_GET_NORESUME, HIF_RTPM_ID_PM_QOS_NOTIFY);
1203 		hdd_ctx->runtime_pm_prevented = true;
1204 	} else if (hdd_ctx->runtime_pm_prevented &&
1205 		   wlan_hdd_is_cpu_cxpc_allowed(hdd_ctx, curr_val)) {
1206 		hif_rtpm_put(HIF_RTPM_PUT_NOIDLE, HIF_RTPM_ID_PM_QOS_NOTIFY);
1207 		hdd_ctx->runtime_pm_prevented = false;
1208 	}
1209 
1210 	qdf_spin_unlock_irqrestore(&hdd_ctx->pm_qos_lock);
1211 
1212 	return NOTIFY_DONE;
1213 }
1214 
1215 /** cpuidle_governor_latency_req() is not exported by upstream kernel **/
1216 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) && \
1217 	defined(__ANDROID_COMMON_KERNEL__))
wlan_hdd_is_cpu_pm_qos_in_progress(struct hdd_context * hdd_ctx)1218 bool wlan_hdd_is_cpu_pm_qos_in_progress(struct hdd_context *hdd_ctx)
1219 {
1220 	long long curr_val_ns;
1221 	long long curr_val_us;
1222 	int max_cpu_num;
1223 
1224 	if (!hdd_is_any_sta_connected(hdd_ctx)) {
1225 		hdd_debug("No active wifi connections. Ignore PM QOS vote");
1226 		return false;
1227 	}
1228 
1229 	max_cpu_num  = nr_cpu_ids - 1;
1230 
1231 	/* Get PM QoS vote from last cpu, as no device votes on that cpu
1232 	 * so by default we get global PM QoS vote from last cpu.
1233 	 */
1234 	curr_val_ns = cpuidle_governor_latency_req(max_cpu_num);
1235 	curr_val_us = curr_val_ns / NSEC_PER_USEC;
1236 	hdd_debug("PM QoS current value: %lld", curr_val_us);
1237 	if (!wlan_hdd_is_cpu_cxpc_allowed(hdd_ctx, curr_val_us))
1238 		return true;
1239 	else
1240 		return false;
1241 }
1242 #endif
1243 #endif
1244 
1245 /**
1246  * hdd_get_ipv4_local_interface() - get ipv4 local interface from iface list
1247  * @adapter: Adapter context for which ARP offload is to be configured
1248  *
1249  * Return:
1250  *	ifa - on successful operation,
1251  *	NULL - on failure of operation
1252  */
hdd_get_ipv4_local_interface(struct hdd_adapter * adapter)1253 static struct in_ifaddr *hdd_get_ipv4_local_interface(
1254 				struct hdd_adapter *adapter)
1255 {
1256 	struct in_ifaddr **ifap = NULL;
1257 	struct in_ifaddr *ifa = NULL;
1258 	struct in_device *in_dev;
1259 
1260 	in_dev = __in_dev_get_rtnl(adapter->dev);
1261 	if (in_dev) {
1262 		for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
1263 			     ifap = &ifa->ifa_next) {
1264 			if (!strcmp(adapter->dev->name, ifa->ifa_label)) {
1265 				/* if match break */
1266 				return ifa;
1267 			}
1268 		}
1269 	}
1270 	ifa = NULL;
1271 
1272 	return ifa;
1273 }
1274 
hdd_enable_arp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)1275 void hdd_enable_arp_offload(struct hdd_adapter *adapter,
1276 			    struct wlan_objmgr_vdev *vdev,
1277 			    enum pmo_offload_trigger trigger)
1278 {
1279 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1280 	struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc;
1281 	QDF_STATUS status;
1282 	struct pmo_arp_req *arp_req;
1283 	struct in_ifaddr *ifa;
1284 	uint8_t vdev_id;
1285 
1286 	hdd_enter();
1287 
1288 	arp_req = qdf_mem_malloc(sizeof(*arp_req));
1289 	if (!arp_req)
1290 		return;
1291 
1292 	vdev_id =  wlan_vdev_get_id(vdev);
1293 
1294 	arp_req->psoc = psoc;
1295 	arp_req->vdev_id = vdev_id;
1296 	arp_req->trigger = trigger;
1297 
1298 	status = ucfg_pmo_check_arp_offload(psoc, trigger, vdev_id);
1299 	if (QDF_IS_STATUS_ERROR(status)) {
1300 		hdd_debug("ARP offload not required");
1301 		goto free_req;
1302 	}
1303 
1304 	if (ucfg_pmo_get_arp_ns_offload_dynamic_disable(vdev)) {
1305 		hdd_debug("Dynamic arp ns offload disabled");
1306 		ucfg_pmo_flush_arp_offload_req(vdev);
1307 		goto skip_cache_arp;
1308 	}
1309 
1310 	ifa = hdd_get_ipv4_local_interface(adapter);
1311 	if (!ifa || !ifa->ifa_local) {
1312 		hdd_info("IP Address is not assigned");
1313 		status = QDF_STATUS_NOT_INITIALIZED;
1314 		goto free_req;
1315 	}
1316 
1317 	arp_req->ipv4_addr = (uint32_t)ifa->ifa_local;
1318 
1319 	status = ucfg_pmo_cache_arp_offload_req(arp_req);
1320 	if (QDF_IS_STATUS_ERROR(status)) {
1321 		hdd_err("failed to cache arp offload req; status:%d", status);
1322 		goto free_req;
1323 	}
1324 
1325 skip_cache_arp:
1326 	status = ucfg_pmo_enable_arp_offload_in_fwr(vdev, trigger);
1327 	if (QDF_IS_STATUS_ERROR(status)) {
1328 		hdd_err("failed arp offload config in fw; status:%d", status);
1329 		goto free_req;
1330 	}
1331 
1332 	hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD, PMO_OFFLOAD_ENABLE);
1333 
1334 free_req:
1335 	qdf_mem_free(arp_req);
1336 }
1337 
1338 #ifdef WLAN_FEATURE_ICMP_OFFLOAD
1339 /**
1340  * hdd_fill_ipv4_addr() - fill IPv4 addresses
1341  * @adapter: Adapter context for which ICMP offload is to be configured
1342  * @pmo_icmp_req: pointer to ICMP offload request params
1343  *
1344  * This is the IPv4 utility function to populate address.
1345  *
1346  * Return: 0 on success, error number otherwise.
1347  */
hdd_fill_ipv4_addr(struct hdd_adapter * adapter,struct pmo_icmp_offload * pmo_icmp_req)1348 static int hdd_fill_ipv4_addr(struct hdd_adapter *adapter,
1349 			      struct pmo_icmp_offload *pmo_icmp_req)
1350 {
1351 	struct in_ifaddr *ifa;
1352 	uint8_t ipv4_addr_array[QDF_IPV4_ADDR_SIZE];
1353 	int i;
1354 
1355 	ifa = hdd_get_ipv4_local_interface(adapter);
1356 	if (!ifa || !ifa->ifa_local) {
1357 		hdd_debug("IP Address is not assigned");
1358 		return -EINVAL;
1359 	}
1360 
1361 	/* converting u32 to IPv4 address */
1362 	for (i = 0; i < QDF_IPV4_ADDR_SIZE; i++)
1363 		ipv4_addr_array[i] = (ifa->ifa_local >> i * 8) & 0xff;
1364 
1365 	qdf_mem_copy(pmo_icmp_req->ipv4_addr, &ipv4_addr_array,
1366 		     QDF_IPV4_ADDR_SIZE);
1367 
1368 	return 0;
1369 }
1370 
1371 /**
1372  * hdd_fill_ipv6_addr() - fill IPv6 addresses
1373  * @adapter: Adapter context for which ICMP offload is to be configured
1374  * @pmo_icmp_req: pointer to ICMP offload request params
1375  *
1376  * This is the IPv6 utility function to populate addresses.
1377  *
1378  * Return: 0 on success, error number otherwise.
1379  */
hdd_fill_ipv6_addr(struct hdd_adapter * adapter,struct pmo_icmp_offload * pmo_icmp_req)1380 static int hdd_fill_ipv6_addr(struct hdd_adapter *adapter,
1381 			      struct pmo_icmp_offload *pmo_icmp_req)
1382 {
1383 	struct inet6_dev *in6_dev;
1384 	struct pmo_ns_req *ns_req;
1385 	int i, errno;
1386 
1387 	in6_dev = __in6_dev_get(adapter->dev);
1388 	if (!in6_dev) {
1389 		hdd_err_rl("IPv6 dev does not exist");
1390 		return -EINVAL;
1391 	}
1392 
1393 	ns_req = qdf_mem_malloc(sizeof(*ns_req));
1394 	if (!ns_req)
1395 		return -ENOMEM;
1396 
1397 	ns_req->count = 0;
1398 	/* Unicast Addresses */
1399 	errno = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
1400 				      ns_req->ipv6_addr_type, ns_req->scope,
1401 				      &ns_req->count);
1402 	if (errno) {
1403 		hdd_debug("Reached Max IPv6 supported address %d",
1404 			  ns_req->count);
1405 		goto free_req;
1406 	}
1407 	/* Anycast Addresses */
1408 	errno = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
1409 				      ns_req->ipv6_addr_type, ns_req->scope,
1410 				      &ns_req->count);
1411 	if (errno) {
1412 		hdd_debug("Reached Max IPv6 supported address %d",
1413 			  ns_req->count);
1414 		goto free_req;
1415 	}
1416 
1417 	pmo_icmp_req->ipv6_count = ns_req->count;
1418 	for (i = 0; i < pmo_icmp_req->ipv6_count; i++) {
1419 		qdf_mem_copy(&pmo_icmp_req->ipv6_addr[i], &ns_req->ipv6_addr[i],
1420 			     QDF_IPV6_ADDR_SIZE);
1421 	}
1422 
1423 free_req:
1424 	qdf_mem_free(ns_req);
1425 	return errno;
1426 }
1427 
hdd_enable_icmp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)1428 void hdd_enable_icmp_offload(struct hdd_adapter *adapter,
1429 			     struct wlan_objmgr_vdev *vdev,
1430 			     enum pmo_offload_trigger trigger)
1431 {
1432 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1433 	struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc;
1434 	struct pmo_icmp_offload *pmo_icmp_req;
1435 	bool is_icmp_enable;
1436 	QDF_STATUS status;
1437 	uint8_t vdev_id;
1438 
1439 	is_icmp_enable = ucfg_pmo_is_icmp_offload_enabled(psoc);
1440 	if (!is_icmp_enable) {
1441 		hdd_debug("ICMP Offload not enabled");
1442 		return;
1443 	}
1444 
1445 	pmo_icmp_req = qdf_mem_malloc(sizeof(*pmo_icmp_req));
1446 	if (!pmo_icmp_req)
1447 		return;
1448 
1449 	vdev_id = wlan_vdev_get_id(vdev);
1450 	status = ucfg_pmo_check_icmp_offload(psoc, vdev_id);
1451 	if (QDF_IS_STATUS_ERROR(status))
1452 		goto free_req;
1453 
1454 	pmo_icmp_req->vdev_id = vdev_id;
1455 	pmo_icmp_req->enable = is_icmp_enable;
1456 	pmo_icmp_req->trigger = trigger;
1457 
1458 	switch (trigger) {
1459 	case pmo_ipv4_change_notify:
1460 		if (hdd_fill_ipv4_addr(adapter, pmo_icmp_req)) {
1461 			hdd_debug("Unable to populate IPv4 Address");
1462 			goto free_req;
1463 		}
1464 		break;
1465 	case pmo_ipv6_change_notify:
1466 		if (hdd_fill_ipv6_addr(adapter, pmo_icmp_req)) {
1467 			hdd_debug("Unable to populate IPv6 Address");
1468 			goto free_req;
1469 		}
1470 		break;
1471 	default:
1472 		QDF_DEBUG_PANIC("The trigger %d is not supported", trigger);
1473 		goto free_req;
1474 	}
1475 
1476 	status = ucfg_pmo_config_icmp_offload(psoc, pmo_icmp_req);
1477 	if (QDF_IS_STATUS_ERROR(status))
1478 		hdd_err_rl("icmp offload config in fw failed: %d", status);
1479 
1480 free_req:
1481 	qdf_mem_free(pmo_icmp_req);
1482 }
1483 #endif
1484 
hdd_disable_arp_offload(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,enum pmo_offload_trigger trigger)1485 void hdd_disable_arp_offload(struct hdd_adapter *adapter,
1486 			     struct wlan_objmgr_vdev *vdev,
1487 			     enum pmo_offload_trigger trigger)
1488 {
1489 	QDF_STATUS status;
1490 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1491 
1492 	hdd_enter();
1493 
1494 	status = ucfg_pmo_check_arp_offload(hdd_ctx->psoc, trigger,
1495 					    wlan_vdev_get_id(vdev));
1496 	if (status != QDF_STATUS_SUCCESS) {
1497 		hdd_debug("Flushing of ARP offload not required");
1498 		return;
1499 	}
1500 
1501 	status = ucfg_pmo_flush_arp_offload_req(vdev);
1502 	if (status != QDF_STATUS_SUCCESS) {
1503 		hdd_err("Failed to flush arp Offload");
1504 		return;
1505 	}
1506 
1507 	status = ucfg_pmo_disable_arp_offload_in_fwr(vdev, trigger);
1508 	if (status == QDF_STATUS_SUCCESS)
1509 		hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD,
1510 			PMO_OFFLOAD_DISABLE);
1511 	else
1512 		hdd_info("fail to disable arp offload");
1513 }
1514 
hdd_enable_mc_addr_filtering(struct hdd_adapter * adapter,enum pmo_offload_trigger trigger)1515 void hdd_enable_mc_addr_filtering(struct hdd_adapter *adapter,
1516 				  enum pmo_offload_trigger trigger)
1517 {
1518 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1519 	QDF_STATUS status;
1520 
1521 	if (wlan_hdd_validate_context(hdd_ctx))
1522 		return;
1523 
1524 	if (!hdd_cm_is_vdev_associated(adapter->deflink))
1525 		return;
1526 
1527 	status = ucfg_pmo_enable_mc_addr_filtering_in_fwr(
1528 						hdd_ctx->psoc,
1529 						adapter->deflink->vdev_id,
1530 						trigger);
1531 	if (QDF_IS_STATUS_ERROR(status))
1532 		hdd_debug("failed to enable mc list; status:%d", status);
1533 
1534 }
1535 
hdd_disable_mc_addr_filtering(struct hdd_adapter * adapter,enum pmo_offload_trigger trigger)1536 void hdd_disable_mc_addr_filtering(struct hdd_adapter *adapter,
1537 				   enum pmo_offload_trigger trigger)
1538 {
1539 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1540 	QDF_STATUS status;
1541 
1542 	if (wlan_hdd_validate_context(hdd_ctx))
1543 		return;
1544 
1545 	status = ucfg_pmo_disable_mc_addr_filtering_in_fwr(
1546 						hdd_ctx->psoc,
1547 						adapter->deflink->vdev_id,
1548 						trigger);
1549 	if (QDF_IS_STATUS_ERROR(status))
1550 		hdd_err("failed to disable mc list; status:%d", status);
1551 }
1552 
hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params * mc_list_config)1553 int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config)
1554 {
1555 	QDF_STATUS status;
1556 
1557 	status = ucfg_pmo_cache_mc_addr_list(mc_list_config);
1558 
1559 	return qdf_status_to_os_return(status);
1560 }
1561 
hdd_disable_and_flush_mc_addr_list(struct hdd_adapter * adapter,enum pmo_offload_trigger trigger)1562 void hdd_disable_and_flush_mc_addr_list(struct hdd_adapter *adapter,
1563 					enum pmo_offload_trigger trigger)
1564 {
1565 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1566 	QDF_STATUS status;
1567 
1568 	/* disable mc list first because the mc list is cached in PMO */
1569 	status = ucfg_pmo_disable_mc_addr_filtering_in_fwr(
1570 						hdd_ctx->psoc,
1571 						adapter->deflink->vdev_id,
1572 						trigger);
1573 	if (QDF_IS_STATUS_ERROR(status))
1574 		hdd_debug("failed to disable mc list; status:%d", status);
1575 
1576 	status = ucfg_pmo_flush_mc_addr_list(hdd_ctx->psoc,
1577 					     adapter->deflink->vdev_id);
1578 	if (QDF_IS_STATUS_ERROR(status))
1579 		hdd_debug("failed to flush mc list; status:%d", status);
1580 }
1581 
1582 /**
1583  * hdd_update_conn_state_mask() - record info needed by wma_suspend_req
1584  * @adapter: adapter to get info from
1585  * @conn_state_mask: mask of connection info
1586  *
1587  * currently only need to send connection info.
1588  */
hdd_update_conn_state_mask(struct hdd_adapter * adapter,uint32_t * conn_state_mask)1589 static void hdd_update_conn_state_mask(struct hdd_adapter *adapter,
1590 				       uint32_t *conn_state_mask)
1591 {
1592 	if (hdd_cm_is_vdev_associated(adapter->deflink))
1593 		*conn_state_mask |= (1 << adapter->deflink->vdev_id);
1594 }
1595 
1596 /**
1597  * hdd_suspend_wlan() - Driver suspend function
1598  *
1599  * Return: 0 on success else error code.
1600  */
1601 static int
hdd_suspend_wlan(void)1602 hdd_suspend_wlan(void)
1603 {
1604 	struct hdd_context *hdd_ctx;
1605 	QDF_STATUS status;
1606 	struct hdd_adapter *adapter = NULL, *next_adapter = NULL;
1607 	uint32_t conn_state_mask = 0;
1608 	struct wlan_hdd_link_info *link_info;
1609 
1610 	hdd_info("WLAN being suspended by OS");
1611 
1612 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1613 	if (!hdd_ctx)
1614 		return -EINVAL;
1615 
1616 	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
1617 		hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!",
1618 			 cds_get_driver_state());
1619 		return -EINVAL;
1620 	}
1621 
1622 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
1623 					   NET_DEV_HOLD_SUSPEND_WLAN) {
1624 		hdd_adapter_for_each_active_link_info(adapter, link_info) {
1625 			if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
1626 				continue;
1627 
1628 			if (adapter->device_mode == QDF_STA_MODE)
1629 				status = hdd_enable_default_pkt_filters(
1630 						hdd_ctx, link_info->vdev_id);
1631 
1632 			/* Configure supported OffLoads */
1633 			hdd_enable_host_offloads(adapter, pmo_apps_suspend);
1634 			hdd_update_conn_state_mask(adapter, &conn_state_mask);
1635 		}
1636 		hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_SUSPEND_WLAN);
1637 	}
1638 
1639 	status = ucfg_pmo_psoc_user_space_suspend_req(hdd_ctx->psoc,
1640 						      QDF_SYSTEM_SUSPEND);
1641 	if (status != QDF_STATUS_SUCCESS)
1642 		return -EAGAIN;
1643 
1644 	hdd_ctx->hdd_wlan_suspended = true;
1645 
1646 	ucfg_dp_suspend_wlan(hdd_ctx->psoc);
1647 
1648 	hdd_configure_sar_sleep_index(hdd_ctx);
1649 
1650 	hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND);
1651 
1652 	return 0;
1653 }
1654 
1655 /**
1656  * hdd_resume_wlan() - Driver resume function
1657  *
1658  * Return: 0 on success else error code.
1659  */
hdd_resume_wlan(void)1660 static int hdd_resume_wlan(void)
1661 {
1662 	struct hdd_context *hdd_ctx;
1663 	struct hdd_adapter *adapter, *next_adapter = NULL;
1664 	QDF_STATUS status;
1665 	struct wlan_hdd_link_info *link_info;
1666 
1667 	hdd_info("WLAN being resumed by OS");
1668 
1669 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1670 	if (!hdd_ctx)
1671 		return -EINVAL;
1672 
1673 	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
1674 		hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!",
1675 			 cds_get_driver_state());
1676 		return -EINVAL;
1677 	}
1678 
1679 	hdd_ctx->hdd_wlan_suspended = false;
1680 	hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME);
1681 
1682 	/*loop through all adapters. Concurrency */
1683 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
1684 					   NET_DEV_HOLD_RESUME_WLAN) {
1685 		hdd_adapter_for_each_active_link_info(adapter, link_info) {
1686 			if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
1687 				continue;
1688 
1689 			/* Disable supported OffLoads */
1690 			hdd_disable_host_offloads(adapter, pmo_apps_resume);
1691 
1692 			if (adapter->device_mode == QDF_STA_MODE)
1693 				status = hdd_disable_default_pkt_filters(
1694 						hdd_ctx, link_info->vdev_id);
1695 
1696 			hdd_restart_tsf_sync_post_wlan_resume(adapter);
1697 		}
1698 		hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_RESUME_WLAN);
1699 	}
1700 
1701 	ucfg_ipa_resume(hdd_ctx->pdev);
1702 	ucfg_dp_resume_wlan(hdd_ctx->psoc);
1703 	status = ucfg_pmo_psoc_user_space_resume_req(hdd_ctx->psoc,
1704 						     QDF_SYSTEM_SUSPEND);
1705 	if (QDF_IS_STATUS_ERROR(status))
1706 		return qdf_status_to_os_return(status);
1707 
1708 	hdd_configure_sar_resume_index(hdd_ctx);
1709 
1710 	return 0;
1711 }
1712 
1713 /**
1714  * hdd_pause_ns() - Network stack pause function
1715  * @hdd_ctx:   hdd context
1716  *
1717  * Return: 0 on success else error code.
1718  */
hdd_pause_ns(struct hdd_context * hdd_ctx)1719 static int hdd_pause_ns(struct hdd_context *hdd_ctx)
1720 {
1721 	struct hdd_adapter *adapter = NULL, *next_adapter = NULL;
1722 
1723 	hdd_debug("Pause NS");
1724 
1725 	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
1726 		hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!",
1727 			 cds_get_driver_state());
1728 		return -EINVAL;
1729 	}
1730 
1731 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
1732 					   NET_DEV_HOLD_SUSPEND_WLAN) {
1733 		if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) {
1734 			hdd_adapter_dev_put_debug(adapter,
1735 						  NET_DEV_HOLD_SUSPEND_WLAN);
1736 			continue;
1737 		}
1738 
1739 		/* stop all TX queues before suspend */
1740 		hdd_debug("Disabling queues for dev mode %s",
1741 			  qdf_opmode_str(adapter->device_mode));
1742 		wlan_hdd_netif_queue_control(adapter,
1743 					     WLAN_STOP_ALL_NETIF_QUEUE,
1744 					     WLAN_CONTROL_PATH);
1745 
1746 		hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_SUSPEND_WLAN);
1747 	}
1748 
1749 	return 0;
1750 }
1751 
1752 /**
1753  * hdd_unpause_ns() - Network stack unpause function
1754  * @hdd_ctx:   hdd context
1755  *
1756  * Return: 0 on success else error code.
1757  */
hdd_unpause_ns(struct hdd_context * hdd_ctx)1758 static int hdd_unpause_ns(struct hdd_context *hdd_ctx)
1759 {
1760 	struct hdd_adapter *adapter, *next_adapter = NULL;
1761 
1762 	hdd_debug("Unpause NS");
1763 
1764 	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
1765 		hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!",
1766 			 cds_get_driver_state());
1767 		return -EINVAL;
1768 	}
1769 
1770 	/*loop through all adapters. Concurrency */
1771 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
1772 					   NET_DEV_HOLD_RESUME_WLAN) {
1773 		if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) {
1774 			hdd_adapter_dev_put_debug(adapter,
1775 						  NET_DEV_HOLD_RESUME_WLAN);
1776 			continue;
1777 		}
1778 
1779 		/* wake the tx queues */
1780 		hdd_debug("Enabling queues for dev mode %s",
1781 			  qdf_opmode_str(adapter->device_mode));
1782 		wlan_hdd_netif_queue_control(adapter,
1783 					     WLAN_WAKE_ALL_NETIF_QUEUE,
1784 					     WLAN_CONTROL_PATH);
1785 
1786 		hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_RESUME_WLAN);
1787 	}
1788 
1789 	return 0;
1790 }
hdd_svc_fw_shutdown_ind(struct device * dev)1791 void hdd_svc_fw_shutdown_ind(struct device *dev)
1792 {
1793 	struct hdd_context *hdd_ctx;
1794 
1795 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1796 
1797 	hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
1798 					      WLAN_SVC_FW_SHUTDOWN_IND,
1799 					      NULL, 0) : 0;
1800 }
1801 
1802 /**
1803  * wlan_hdd_set_twt_responder() - wrapper to configure twt responder
1804  * in sap_config
1805  * @hdd_ctx: Pointer to hdd context
1806  * @adapter: Pointer to hostapd hdd adapter
1807  *
1808  * Return: none
1809  */
1810 #if defined(WLAN_SUPPORT_TWT) && \
1811 	((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) || \
1812 	  defined(CFG80211_TWT_RESPONDER_SUPPORT))
wlan_hdd_set_twt_responder(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter)1813 static void wlan_hdd_set_twt_responder(struct hdd_context *hdd_ctx,
1814 				       struct hdd_adapter *adapter)
1815 {
1816 	bool twt_responder;
1817 
1818 	twt_responder =
1819 		adapter->deflink->session.ap.sap_config.cfg80211_twt_responder;
1820 	wlan_hdd_configure_twt_responder(hdd_ctx, twt_responder);
1821 }
1822 #else
wlan_hdd_set_twt_responder(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter)1823 static inline void wlan_hdd_set_twt_responder(struct hdd_context *hdd_ctx,
1824 					      struct hdd_adapter *adapter)
1825 {
1826 }
1827 #endif
1828 
1829 /**
1830  * hdd_ssr_restart_sap() - restart sap on SSR
1831  * @hdd_ctx:   hdd context
1832  *
1833  * Return:     nothing
1834  */
hdd_ssr_restart_sap(struct hdd_context * hdd_ctx)1835 static void hdd_ssr_restart_sap(struct hdd_context *hdd_ctx)
1836 {
1837 	struct hdd_adapter *adapter, *next_adapter = NULL;
1838 
1839 	hdd_enter();
1840 
1841 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
1842 					   NET_DEV_HOLD_SSR_RESTART_SAP) {
1843 		if (adapter->device_mode != QDF_SAP_MODE)
1844 			goto next_adapter;
1845 
1846 		if (test_bit(SOFTAP_INIT_DONE, &adapter->deflink->link_flags)) {
1847 			hdd_debug("Restart prev SAP session, event_flags 0x%lx, link_flags 0x%lx(%s)",
1848 				  adapter->event_flags,
1849 				  adapter->deflink->link_flags,
1850 				  adapter->dev->name);
1851 			wlan_hdd_set_twt_responder(hdd_ctx, adapter);
1852 			wlan_hdd_start_sap(adapter->deflink, true);
1853 		}
1854 next_adapter:
1855 		hdd_adapter_dev_put_debug(adapter,
1856 					  NET_DEV_HOLD_SSR_RESTART_SAP);
1857 	}
1858 
1859 	hdd_exit();
1860 }
1861 
hdd_wlan_shutdown(void)1862 QDF_STATUS hdd_wlan_shutdown(void)
1863 {
1864 	struct hdd_context *hdd_ctx;
1865 	struct hdd_adapter *adapter;
1866 	struct wlan_objmgr_vdev *vdev;
1867 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1868 
1869 	hdd_info("WLAN driver shutting down!");
1870 
1871 	/* Get the HDD context. */
1872 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1873 	if (!hdd_ctx)
1874 		return QDF_STATUS_E_FAILURE;
1875 
1876 	if (ucfg_ipa_is_enabled()) {
1877 		ucfg_ipa_uc_force_pipe_shutdown(hdd_ctx->pdev);
1878 
1879 		if (pld_is_fw_rejuvenate(hdd_ctx->parent_dev) ||
1880 		    pld_is_pdr(hdd_ctx->parent_dev))
1881 			ucfg_ipa_fw_rejuvenate_send_msg(hdd_ctx->pdev);
1882 	}
1883 
1884 	hdd_set_connection_in_progress(false);
1885 
1886 	hdd_debug("Invoking packetdump deregistration API");
1887 	wlan_deregister_txrx_packetdump(OL_TXRX_PDEV_ID);
1888 
1889 	/* resume wlan threads before adapter reset which does vdev destroy */
1890 	if (hdd_ctx->is_scheduler_suspended) {
1891 		scheduler_resume();
1892 		hdd_ctx->is_scheduler_suspended = false;
1893 		hdd_ctx->is_wiphy_suspended = false;
1894 		hdd_ctx->hdd_wlan_suspended = false;
1895 		ucfg_pmo_resume_all_components(hdd_ctx->psoc,
1896 					       QDF_SYSTEM_SUSPEND);
1897 	}
1898 
1899 	wlan_hdd_rx_thread_resume(hdd_ctx);
1900 
1901 	if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) !=
1902 						PACKET_CAPTURE_MODE_DISABLE) {
1903 		adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE);
1904 		if (adapter) {
1905 			vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
1906 							   WLAN_OSIF_POWER_ID);
1907 			if (vdev) {
1908 				ucfg_pkt_capture_resume_mon_thread(vdev);
1909 				hdd_objmgr_put_vdev_by_user(
1910 					vdev, WLAN_OSIF_POWER_ID);
1911 			} else {
1912 				hdd_err("vdev is NULL");
1913 			}
1914 		}
1915 	}
1916 
1917 	hdd_reset_all_adapters(hdd_ctx);
1918 
1919 	ucfg_ipa_uc_ssr_cleanup(hdd_ctx->pdev);
1920 
1921 	/* Flush cached rx frame queue */
1922 	if (soc)
1923 		cdp_flush_cache_rx_queue(soc);
1924 
1925 	/* De-register the HDD callbacks */
1926 	hdd_deregister_cb(hdd_ctx);
1927 
1928 	hdd_wlan_stop_modules(hdd_ctx, false);
1929 
1930 	hdd_lpass_notify_stop(hdd_ctx);
1931 
1932 	qdf_set_smmu_fault_state(false);
1933 	hdd_info("WLAN driver shutdown complete");
1934 
1935 	return QDF_STATUS_SUCCESS;
1936 }
1937 
1938 #ifdef FEATURE_WLAN_DIAG_SUPPORT
1939 /**
1940  * hdd_wlan_ssr_reinit_event() - send ssr reinit state
1941  *
1942  * This Function send send ssr reinit state diag event
1943  *
1944  * Return: void.
1945  */
hdd_wlan_ssr_reinit_event(void)1946 static void hdd_wlan_ssr_reinit_event(void)
1947 {
1948 	WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit);
1949 	qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit));
1950 	ssr_reinit.status = SSR_SUB_SYSTEM_REINIT;
1951 	WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit,
1952 					EVENT_WLAN_SSR_REINIT_SUBSYSTEM);
1953 }
1954 #else
hdd_wlan_ssr_reinit_event(void)1955 static inline void hdd_wlan_ssr_reinit_event(void)
1956 {
1957 
1958 }
1959 #endif
1960 
1961 #ifdef WLAN_FEATURE_DBAM_CONFIG
1962 /**
1963  * hdd_restore_dbam_config() - restore and send dbam config to fw
1964  * @hdd_ctx: HDD context
1965  *
1966  * This function is used to send  store dbam config to fw
1967  * in case of wlan re-init
1968  *
1969  * Return: void
1970  */
hdd_restore_dbam_config(struct hdd_context * hdd_ctx)1971 static void hdd_restore_dbam_config(struct hdd_context *hdd_ctx)
1972 {
1973 	struct hdd_adapter *adapter, *next_adapter = NULL;
1974 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER;
1975 
1976 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
1977 					   dbgid) {
1978 		if (hdd_is_interface_up(adapter) &&
1979 		    adapter->is_dbam_configured)
1980 			hdd_send_dbam_config(adapter, hdd_ctx->dbam_mode);
1981 		hdd_adapter_dev_put_debug(adapter, dbgid);
1982 	}
1983 }
1984 #else
hdd_restore_dbam_config(struct hdd_context * hdd_ctx)1985 static inline void hdd_restore_dbam_config(struct hdd_context *hdd_ctx)
1986 {
1987 }
1988 #endif
1989 
1990 /**
1991  * hdd_restore_dual_sta_config() - Restore dual sta configuration
1992  * @hdd_ctx: pointer to struct hdd_context
1993  *
1994  * Return: None
1995  */
hdd_restore_dual_sta_config(struct hdd_context * hdd_ctx)1996 static void hdd_restore_dual_sta_config(struct hdd_context *hdd_ctx)
1997 {
1998 	QDF_STATUS status;
1999 	struct hdd_dual_sta_policy *sta_policy;
2000 
2001 	sta_policy = &hdd_ctx->dual_sta_policy;
2002 
2003 	hdd_debug("Restore dual sta config: Primary vdev_id:%d, sta policy:%d",
2004 		  sta_policy->primary_vdev_id,
2005 		  sta_policy->dual_sta_policy);
2006 
2007 	status =
2008 		ucfg_mlme_set_primary_interface(hdd_ctx->psoc,
2009 						sta_policy->primary_vdev_id);
2010 	if (QDF_IS_STATUS_ERROR(status))
2011 		hdd_err("could not set primary interface, %d", status);
2012 
2013 	status =
2014 		ucfg_mlme_set_dual_sta_policy(hdd_ctx->psoc,
2015 					      sta_policy->dual_sta_policy);
2016 	if (QDF_IS_STATUS_ERROR(status))
2017 		hdd_err("failed to set mlme dual sta config");
2018 }
2019 
2020 /**
2021  * hdd_send_default_scan_ies() - send default scan ies to fw
2022  * @hdd_ctx: HDD context
2023  *
2024  * This function is used to send default scan ies to fw
2025  * in case of wlan re-init
2026  *
2027  * Return: void
2028  */
hdd_send_default_scan_ies(struct hdd_context * hdd_ctx)2029 static void hdd_send_default_scan_ies(struct hdd_context *hdd_ctx)
2030 {
2031 	struct hdd_adapter *adapter, *next_adapter = NULL;
2032 
2033 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
2034 					   NET_DEV_HOLD_SEND_DEFAULT_SCAN_IES) {
2035 		if (hdd_is_interface_up(adapter) &&
2036 		    (adapter->device_mode == QDF_STA_MODE ||
2037 		    adapter->device_mode == QDF_P2P_DEVICE_MODE) &&
2038 		    adapter->scan_info.default_scan_ies) {
2039 			sme_set_default_scan_ie(hdd_ctx->mac_handle,
2040 				      adapter->deflink->vdev_id,
2041 				      adapter->scan_info.default_scan_ies,
2042 				      adapter->scan_info.default_scan_ies_len);
2043 		}
2044 		hdd_adapter_dev_put_debug(adapter,
2045 					  NET_DEV_HOLD_SEND_DEFAULT_SCAN_IES);
2046 	}
2047 }
2048 
2049 /**
2050  * hdd_restore_sar_config() - Restore the saved SAR config after SSR
2051  * @hdd_ctx: HDD context
2052  *
2053  * Restore the SAR config that was lost during SSR.
2054  *
2055  * Return: None
2056  */
hdd_restore_sar_config(struct hdd_context * hdd_ctx)2057 static void hdd_restore_sar_config(struct hdd_context *hdd_ctx)
2058 {
2059 	QDF_STATUS status;
2060 
2061 	if (!hdd_ctx->sar_cmd_params)
2062 		return;
2063 
2064 	status = sme_set_sar_power_limits(hdd_ctx->mac_handle,
2065 					  hdd_ctx->sar_cmd_params);
2066 	if (QDF_IS_STATUS_ERROR(status))
2067 		hdd_err("Unable to configured SAR after SSR");
2068 }
2069 
hdd_handle_cached_commands(void)2070 void hdd_handle_cached_commands(void)
2071 {
2072 	struct net_device *net_dev;
2073 	struct hdd_adapter *adapter = NULL;
2074 	struct hdd_context *hdd_ctx;
2075 	struct osif_vdev_sync *vdev_sync_arr = osif_get_vdev_sync_arr();
2076 	struct osif_vdev_sync *vdev_sync;
2077 	int i;
2078 	uint8_t cmd_id;
2079 
2080 	/* Get the HDD context */
2081 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
2082 	if (!hdd_ctx)
2083 		return;
2084 
2085 	for (i = 0; i < WLAN_MAX_VDEVS; i++) {
2086 		vdev_sync = vdev_sync_arr + i;
2087 		if (!vdev_sync || !vdev_sync->in_use)
2088 			continue;
2089 
2090 		cmd_id = osif_vdev_get_cached_cmd(vdev_sync);
2091 		net_dev = vdev_sync->net_dev;
2092 		if (net_dev) {
2093 			adapter = WLAN_HDD_GET_PRIV_PTR(
2094 					(struct net_device *)net_dev);
2095 			if (!adapter)
2096 				continue;
2097 		} else {
2098 			continue;
2099 		}
2100 
2101 		switch (cmd_id) {
2102 		case NO_COMMAND:
2103 			break;
2104 		case INTERFACE_DOWN:
2105 			hdd_debug("Handling cached interface down command for %s",
2106 				  adapter->dev->name);
2107 
2108 			if (adapter->device_mode == QDF_SAP_MODE ||
2109 			    adapter->device_mode == QDF_P2P_GO_MODE)
2110 				hdd_hostapd_stop_no_trans(net_dev);
2111 			else
2112 				hdd_stop_no_trans(net_dev);
2113 
2114 			osif_vdev_cache_command(vdev_sync, NO_COMMAND);
2115 			break;
2116 		default:
2117 			break;
2118 		}
2119 	}
2120 }
2121 
hdd_wlan_re_init(void)2122 QDF_STATUS hdd_wlan_re_init(void)
2123 {
2124 	struct hdd_context *hdd_ctx = NULL;
2125 	struct hdd_adapter *adapter;
2126 	int ret;
2127 	bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT;
2128 	bool value;
2129 
2130 	hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
2131 
2132 	/* Get the HDD context */
2133 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
2134 	if (!hdd_ctx)
2135 		goto err_ctx_null;
2136 
2137 	bug_on_reinit_failure = hdd_ctx->config->bug_on_reinit_failure;
2138 
2139 	adapter = hdd_get_first_valid_adapter(hdd_ctx);
2140 	if (!adapter)
2141 		hdd_err("Failed to get adapter");
2142 
2143 	ret = hdd_wlan_start_modules(hdd_ctx, true);
2144 	if (ret) {
2145 		hdd_err("Failed to start wlan after error");
2146 		goto err_re_init;
2147 	}
2148 
2149 	hdd_update_hw_sw_info(hdd_ctx);
2150 
2151 	wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
2152 				WLAN_SVC_FW_CRASHED_IND, NULL, 0);
2153 
2154 	/* Restart all adapters */
2155 	hdd_start_all_adapters(hdd_ctx, false);
2156 
2157 	hdd_init_scan_reject_params(hdd_ctx);
2158 	hdd_ctx->bt_coex_mode_set = false;
2159 
2160 	/* Allow the phone to go to sleep */
2161 	hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
2162 	/* set chip power save failure detected callback */
2163 	sme_set_chip_pwr_save_fail_cb(hdd_ctx->mac_handle,
2164 				      hdd_chip_pwr_save_fail_detected_cb);
2165 
2166 	hdd_restore_thermal_mitigation_config(hdd_ctx);
2167 	hdd_restore_sar_config(hdd_ctx);
2168 
2169 	hdd_send_default_scan_ies(hdd_ctx);
2170 	hdd_restore_dual_sta_config(hdd_ctx);
2171 	hdd_restore_dbam_config(hdd_ctx);
2172 	hdd_info("WLAN host driver reinitiation completed!");
2173 
2174 	ucfg_mlme_get_sap_internal_restart(hdd_ctx->psoc, &value);
2175 	if (value)
2176 		hdd_ssr_restart_sap(hdd_ctx);
2177 	hdd_wlan_ssr_reinit_event();
2178 
2179 	if (hdd_ctx->is_wiphy_suspended)
2180 		hdd_ctx->is_wiphy_suspended = false;
2181 
2182 	if (hdd_ctx->hdd_wlan_suspended)
2183 		hdd_ctx->hdd_wlan_suspended = false;
2184 
2185 	return QDF_STATUS_SUCCESS;
2186 
2187 err_re_init:
2188 	qdf_dp_trace_deinit();
2189 
2190 err_ctx_null:
2191 	/* Allow the phone to go to sleep */
2192 	hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
2193 	if (bug_on_reinit_failure)
2194 		QDF_BUG(0);
2195 	return -EPERM;
2196 }
2197 
wlan_hdd_set_powersave(struct wlan_hdd_link_info * link_info,bool allow_power_save,uint32_t timeout)2198 int wlan_hdd_set_powersave(struct wlan_hdd_link_info *link_info,
2199 			   bool allow_power_save, uint32_t timeout)
2200 {
2201 	struct hdd_adapter *adapter = link_info->adapter;
2202 	struct hdd_context *hdd_ctx;
2203 	QDF_STATUS status;
2204 	struct hdd_station_ctx *sta_ctx;
2205 
2206 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2207 	if (!hdd_ctx) {
2208 		hdd_err("hdd context is NULL");
2209 		return -EINVAL;
2210 	}
2211 
2212 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
2213 		return -EINVAL;
2214 
2215 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
2216 
2217 	status = sme_ps_set_powersave(
2218 				hdd_ctx->mac_handle, link_info->vdev_id,
2219 				allow_power_save, timeout,
2220 				sta_ctx->ap_supports_immediate_power_save);
2221 	if (!allow_power_save && adapter->device_mode == QDF_STA_MODE)
2222 		hdd_twt_del_dialog_in_ps_disable(hdd_ctx,
2223 						 &sta_ctx->conn_info.bssid,
2224 						 link_info->vdev_id);
2225 
2226 	return qdf_status_to_os_return(status);
2227 }
2228 
wlan_hdd_print_suspend_fail_stats(struct hdd_context * hdd_ctx)2229 static void wlan_hdd_print_suspend_fail_stats(struct hdd_context *hdd_ctx)
2230 {
2231 	struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats;
2232 
2233 	hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d",
2234 		stats->suspend_fail[SUSPEND_FAIL_IPA],
2235 		stats->suspend_fail[SUSPEND_FAIL_RADAR],
2236 		stats->suspend_fail[SUSPEND_FAIL_ROAM],
2237 		stats->suspend_fail[SUSPEND_FAIL_SCAN],
2238 		stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]);
2239 }
2240 
wlan_hdd_inc_suspend_stats(struct hdd_context * hdd_ctx,enum suspend_fail_reason reason)2241 void wlan_hdd_inc_suspend_stats(struct hdd_context *hdd_ctx,
2242 				enum suspend_fail_reason reason)
2243 {
2244 	wlan_hdd_print_suspend_fail_stats(hdd_ctx);
2245 	hdd_ctx->suspend_resume_stats.suspend_fail[reason]++;
2246 	wlan_hdd_print_suspend_fail_stats(hdd_ctx);
2247 }
2248 
2249 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
2250 static inline void
hdd_sched_scan_results(struct wiphy * wiphy,uint64_t reqid)2251 hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
2252 {
2253 	cfg80211_sched_scan_results(wiphy);
2254 }
2255 #else
2256 static inline void
hdd_sched_scan_results(struct wiphy * wiphy,uint64_t reqid)2257 hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
2258 {
2259 	cfg80211_sched_scan_results(wiphy, reqid);
2260 }
2261 #endif
2262 
2263 /**
2264  * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
2265  * @wiphy: Pointer to wiphy
2266  *
2267  * This API is called when cfg80211 driver resumes driver updates
2268  * latest sched_scan scan result(if any) to cfg80211 database
2269  *
2270  * Return: integer status
2271  */
__wlan_hdd_cfg80211_resume_wlan(struct wiphy * wiphy)2272 static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
2273 {
2274 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2275 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2276 	struct hdd_adapter *adapter;
2277 	struct wlan_objmgr_vdev *vdev;
2278 	int exit_code;
2279 
2280 	hdd_enter();
2281 
2282 	if (cds_is_driver_recovering()) {
2283 		hdd_debug("Driver is recovering; Skipping resume");
2284 		exit_code = 0;
2285 		goto exit_with_code;
2286 	}
2287 
2288 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam() ||
2289 	    QDF_GLOBAL_MONITOR_MODE == hdd_get_conparam()) {
2290 		hdd_err("Command not allowed in mode %d",
2291 			hdd_get_conparam());
2292 		exit_code = -EINVAL;
2293 		goto exit_with_code;
2294 	}
2295 
2296 	if (ucfg_pmo_get_suspend_mode(hdd_ctx->psoc) == PMO_SUSPEND_NONE) {
2297 		hdd_info_rl("Suspend is not supported");
2298 		return -EINVAL;
2299 	}
2300 
2301 	if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2302 		hdd_debug("Driver is not enabled; Skipping resume");
2303 		exit_code = 0;
2304 		goto exit_with_code;
2305 	}
2306 
2307 	status = hdd_resume_wlan();
2308 	if (status != QDF_STATUS_SUCCESS) {
2309 		exit_code = 0;
2310 		goto exit_with_code;
2311 	}
2312 	/* Resume control path scheduler */
2313 	if (hdd_ctx->is_scheduler_suspended) {
2314 		scheduler_resume();
2315 		hdd_ctx->is_scheduler_suspended = false;
2316 	}
2317 	/* Resume all components registered to pmo */
2318 	status = ucfg_pmo_resume_all_components(hdd_ctx->psoc,
2319 						QDF_SYSTEM_SUSPEND);
2320 
2321 	/* Unpause NS no matter of the return value of pmo_resume */
2322 	hdd_unpause_ns(hdd_ctx);
2323 
2324 	if (status != QDF_STATUS_SUCCESS) {
2325 		exit_code = 0;
2326 		goto exit_with_code;
2327 	}
2328 	/* Resume tlshim Rx thread */
2329 	if (ucfg_dp_is_rx_common_thread_enabled(hdd_ctx->psoc))
2330 		wlan_hdd_rx_thread_resume(hdd_ctx);
2331 
2332 	if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) !=
2333 						PACKET_CAPTURE_MODE_DISABLE) {
2334 		adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE);
2335 		if (adapter) {
2336 			vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
2337 							   WLAN_OSIF_POWER_ID);
2338 			if (vdev) {
2339 				ucfg_pkt_capture_resume_mon_thread(vdev);
2340 				hdd_objmgr_put_vdev_by_user(
2341 					vdev, WLAN_OSIF_POWER_ID);
2342 			} else {
2343 				hdd_err("vdev is NULL");
2344 			}
2345 		}
2346 	}
2347 
2348 	ucfg_pmo_notify_system_resume(hdd_ctx->psoc);
2349 	wlan_hdd_resume_pmo_twt(hdd_ctx);
2350 
2351 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2352 		   TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
2353 		   NO_SESSION, hdd_ctx->is_wiphy_suspended);
2354 
2355 	hdd_ctx->is_wiphy_suspended = false;
2356 
2357 	hdd_ctx->suspend_resume_stats.resumes++;
2358 	exit_code = 0;
2359 
2360 exit_with_code:
2361 	hdd_exit();
2362 	return exit_code;
2363 }
2364 
_wlan_hdd_cfg80211_resume_wlan(struct wiphy * wiphy)2365 static int _wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
2366 {
2367 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2368 	qdf_runtime_lock_t *suspend_lock;
2369 	int errno;
2370 
2371 	if (!hdd_ctx) {
2372 		hdd_err_rl("hdd context is null");
2373 		return -ENODEV;
2374 	}
2375 
2376 	/* If Wifi is off, return success for system resume */
2377 	if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2378 		hdd_debug("Driver Modules not Enabled ");
2379 		return 0;
2380 	}
2381 
2382 	/*
2383 	 * Return success if recovery is in progress, otherwise, linux kernel
2384 	 * will shutdown all interfaces in wiphy_resume.
2385 	 */
2386 	if (cds_is_driver_recovering()) {
2387 		hdd_debug("Recovery in progress");
2388 		return 0;
2389 	}
2390 
2391 	errno = wlan_hdd_validate_context(hdd_ctx);
2392 	if (errno)
2393 		return errno;
2394 
2395 	suspend_lock = &hdd_ctx->runtime_context.system_suspend;
2396 	errno = qdf_runtime_pm_allow_suspend(suspend_lock);
2397 	if (errno)
2398 		return errno;
2399 
2400 	errno = __wlan_hdd_cfg80211_resume_wlan(wiphy);
2401 
2402 	/* It may happen during cfg80211 suspend this timer is stopped.
2403 	 * This means that if
2404 	 * 1) work was queued in the workqueue, it was removed from the
2405 	 *    workqueue and suspend proceeded.
2406 	 * 2) The work was scheduled and cfg80211 suspend waited for this
2407 	 *    work to complete and then suspend proceeded.
2408 	 * So here in cfg80211 resume, check if no interface is up and
2409 	 * the module state is enabled then trigger idle timer start.
2410 	 */
2411 	if (!hdd_is_any_interface_open(hdd_ctx) &&
2412 	    hdd_ctx->driver_status == DRIVER_MODULES_ENABLED)
2413 		hdd_psoc_idle_timer_start(hdd_ctx);
2414 
2415 	return errno;
2416 }
2417 
wlan_hdd_cfg80211_resume_wlan(struct wiphy * wiphy)2418 int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
2419 {
2420 	struct osif_psoc_sync *psoc_sync;
2421 	int errno;
2422 
2423 	errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
2424 	if (errno)
2425 		return errno;
2426 
2427 	errno = _wlan_hdd_cfg80211_resume_wlan(wiphy);
2428 
2429 	osif_psoc_sync_op_stop(psoc_sync);
2430 
2431 	return errno;
2432 }
2433 
hdd_suspend_cb(void)2434 static void hdd_suspend_cb(void)
2435 {
2436 	struct hdd_context *hdd_ctx;
2437 
2438 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
2439 	if (!hdd_ctx)
2440 		return;
2441 
2442 	complete(&hdd_ctx->mc_sus_event_var);
2443 }
2444 
2445 /**
2446  * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
2447  * @wiphy: Pointer to wiphy
2448  * @wow: Pointer to wow
2449  *
2450  * This API is called when cfg80211 driver suspends
2451  *
2452  * Return: integer status
2453  */
__wlan_hdd_cfg80211_suspend_wlan(struct wiphy * wiphy,struct cfg80211_wowlan * wow)2454 static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
2455 				     struct cfg80211_wowlan *wow)
2456 {
2457 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2458 	struct hdd_adapter *adapter, *next_adapter = NULL;
2459 	mac_handle_t mac_handle;
2460 	struct wlan_objmgr_vdev *vdev;
2461 	enum pmo_suspend_mode mode;
2462 	int rc;
2463 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_CFG80211_SUSPEND_WLAN;
2464 	struct hdd_ap_ctx *ap_ctx;
2465 	struct hdd_hostapd_state *hapd_state;
2466 	struct csr_del_sta_params params = {
2467 		.peerMacAddr = QDF_MAC_ADDR_BCAST_INIT,
2468 		.reason_code = REASON_DEAUTH_NETWORK_LEAVING,
2469 		.subtype = SIR_MAC_MGMT_DEAUTH,
2470 	};
2471 	struct wlan_hdd_link_info *link_info;
2472 
2473 	hdd_enter();
2474 
2475 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam() ||
2476 	    QDF_GLOBAL_MONITOR_MODE == hdd_get_conparam()) {
2477 		hdd_err_rl("Command not allowed in mode %d",
2478 			   hdd_get_conparam());
2479 		return -EINVAL;
2480 	}
2481 
2482 	rc = wlan_hdd_validate_context(hdd_ctx);
2483 	if (0 != rc) {
2484 		if (pld_is_low_power_mode(hdd_ctx->parent_dev))
2485 			hdd_debug("low power mode (Deep Sleep/Hibernate)");
2486 		else
2487 			return rc;
2488 	}
2489 
2490 	if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2491 		hdd_debug("Driver Modules not Enabled ");
2492 		return 0;
2493 	}
2494 
2495 	mode = ucfg_pmo_get_suspend_mode(hdd_ctx->psoc);
2496 	if (mode == PMO_SUSPEND_NONE) {
2497 		hdd_info_rl("Suspend is not supported");
2498 		return -EINVAL;
2499 	} else if (mode == PMO_SUSPEND_SHUTDOWN) {
2500 		hdd_info_rl("shutdown suspend should complete in prepare");
2501 		return -EINVAL;
2502 	}
2503 
2504 	mac_handle = hdd_ctx->mac_handle;
2505 
2506 	/* If RADAR detection is in progress (HDD), prevent suspend. The flag
2507 	 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true
2508 	 * until CAC is done for a SoftAP which is in started state.
2509 	 */
2510 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
2511 					   dbgid) {
2512 		hdd_adapter_for_each_active_link_info(adapter, link_info) {
2513 			if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
2514 				continue;
2515 
2516 			if (QDF_SAP_MODE == adapter->device_mode) {
2517 				hapd_state =
2518 					WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info);
2519 				ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info);
2520 				if (BSS_START == hapd_state->bss_state &&
2521 				    true == ap_ctx->dfs_cac_block_tx) {
2522 					hdd_err("RADAR detection in progress, do not allow suspend");
2523 					wlan_hdd_inc_suspend_stats(hdd_ctx,
2524 							   SUSPEND_FAIL_RADAR);
2525 					hdd_adapter_dev_put_debug(adapter,
2526 								  dbgid);
2527 					if (next_adapter)
2528 						hdd_adapter_dev_put_debug(
2529 								next_adapter,
2530 								dbgid);
2531 					return -EAGAIN;
2532 				} else if (!ucfg_pmo_get_enable_sap_suspend(
2533 					   hdd_ctx->psoc)) {
2534 					/* return -EOPNOTSUPP if SAP
2535 					 * does not support suspend
2536 					 */
2537 					hdd_err("SAP does not support suspend!!");
2538 					hdd_adapter_dev_put_debug(adapter,
2539 								  dbgid);
2540 					if (next_adapter)
2541 						hdd_adapter_dev_put_debug(
2542 								next_adapter,
2543 								dbgid);
2544 					return -EOPNOTSUPP;
2545 				} else if (ucfg_pmo_get_disconnect_sap_tdls_in_wow(
2546 					   hdd_ctx->psoc)) {
2547 					hdd_softap_deauth_all_sta(adapter,
2548 								  hapd_state,
2549 								  &params);
2550 				}
2551 			} else if (QDF_P2P_GO_MODE == adapter->device_mode) {
2552 				hapd_state =
2553 					WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info);
2554 				if (!ucfg_pmo_get_enable_sap_suspend(
2555 					   hdd_ctx->psoc)) {
2556 					/* return -EOPNOTSUPP if GO
2557 					 * does not support suspend
2558 					 */
2559 					hdd_err("GO does not support suspend!!");
2560 					hdd_adapter_dev_put_debug(adapter,
2561 								  dbgid);
2562 					if (next_adapter)
2563 						hdd_adapter_dev_put_debug(
2564 								next_adapter,
2565 								dbgid);
2566 					return -EOPNOTSUPP;
2567 				} else if (ucfg_pmo_get_disconnect_sap_tdls_in_wow(
2568 					   hdd_ctx->psoc)) {
2569 					hdd_softap_deauth_all_sta(adapter,
2570 								  hapd_state,
2571 								  &params);
2572 				}
2573 			} else if (QDF_TDLS_MODE == adapter->device_mode &&
2574 				   ucfg_pmo_get_disconnect_sap_tdls_in_wow(
2575 								hdd_ctx->psoc)) {
2576 				vdev = hdd_objmgr_get_vdev_by_user(link_info,
2577 								   WLAN_TDLS_NB_ID);
2578 				if (vdev) {
2579 					ucfg_tdls_teardown_links_sync(hdd_ctx->psoc,
2580 								      vdev);
2581 					hdd_objmgr_put_vdev_by_user(vdev,
2582 								    WLAN_TDLS_NB_ID);
2583 				}
2584 			}
2585 		}
2586 		hdd_adapter_dev_put_debug(adapter, dbgid);
2587 	}
2588 	/* p2p cleanup task based on scheduler */
2589 	ucfg_p2p_cleanup_tx_by_psoc(hdd_ctx->psoc);
2590 	ucfg_p2p_cleanup_roc_by_psoc(hdd_ctx->psoc);
2591 
2592 	if (hdd_is_connection_in_progress(NULL, NULL)) {
2593 		hdd_err_rl("Connection is in progress, rejecting suspend");
2594 		return -EINVAL;
2595 	}
2596 
2597 	/* flush any pending powersave timers */
2598 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
2599 					   dbgid) {
2600 		hdd_adapter_for_each_active_link_info(adapter, link_info) {
2601 			if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
2602 				continue;
2603 
2604 			sme_ps_timer_flush_sync(mac_handle, link_info->vdev_id);
2605 		}
2606 		hdd_adapter_dev_put_debug(adapter, dbgid);
2607 	}
2608 
2609 	hdd_pause_ns(hdd_ctx);
2610 
2611 	/*
2612 	 * Suspend all components registered to pmo, abort ongoing scan and
2613 	 * don't allow new scan any more before scheduler thread suspended.
2614 	 */
2615 	if (ucfg_pmo_suspend_all_components(hdd_ctx->psoc,
2616 					    QDF_SYSTEM_SUSPEND)) {
2617 		hdd_err("Some components not ready to suspend!");
2618 		return -EAGAIN;
2619 	}
2620 
2621 	wlan_hdd_suspend_pmo_twt(hdd_ctx);
2622 
2623 	/*
2624 	 * Suspend IPA early before proceeding to suspend other entities like
2625 	 * firmware to avoid any race conditions.
2626 	 */
2627 	if (ucfg_ipa_suspend(hdd_ctx->pdev)) {
2628 		hdd_err("IPA not ready to suspend!");
2629 		wlan_hdd_inc_suspend_stats(hdd_ctx, SUSPEND_FAIL_IPA);
2630 		goto resume_all_components;
2631 	}
2632 
2633 	/* Suspend control path scheduler */
2634 	scheduler_register_hdd_suspend_callback(hdd_suspend_cb);
2635 	scheduler_set_event_mask(MC_SUSPEND_EVENT);
2636 	scheduler_wake_up_controller_thread();
2637 
2638 	/* Wait for suspend confirmation from scheduler */
2639 	rc = wait_for_completion_timeout(&hdd_ctx->mc_sus_event_var,
2640 		msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
2641 	if (!rc) {
2642 		scheduler_clear_event_mask(MC_SUSPEND_EVENT);
2643 		hdd_err("Failed to stop mc thread");
2644 		goto resume_tx;
2645 	}
2646 	hdd_ctx->is_scheduler_suspended = true;
2647 
2648 	if (ucfg_dp_is_rx_common_thread_enabled(hdd_ctx->psoc)) {
2649 		if (wlan_hdd_rx_thread_suspend(hdd_ctx))
2650 			goto resume_ol_rx;
2651 	}
2652 
2653 	if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) !=
2654 						PACKET_CAPTURE_MODE_DISABLE) {
2655 		adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE);
2656 		if (adapter) {
2657 			vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
2658 							   WLAN_OSIF_POWER_ID);
2659 			if (!vdev) {
2660 				hdd_err("vdev is NULL");
2661 				goto resume_dp_thread;
2662 			}
2663 			if (ucfg_pkt_capture_suspend_mon_thread(vdev)) {
2664 				hdd_objmgr_put_vdev_by_user(
2665 					vdev, WLAN_OSIF_POWER_ID);
2666 				goto resume_dp_thread;
2667 			}
2668 			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
2669 		}
2670 	}
2671 
2672 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2673 		   TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
2674 		   NO_SESSION, hdd_ctx->is_wiphy_suspended);
2675 
2676 	if (hdd_suspend_wlan() < 0) {
2677 		hdd_err("Failed to suspend WLAN");
2678 		goto resume_dp_thread;
2679 	}
2680 
2681 	hdd_ctx->is_wiphy_suspended = true;
2682 
2683 	hdd_exit();
2684 	return 0;
2685 
2686 resume_dp_thread:
2687 	/* Resume packet capture MON thread */
2688 	if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) !=
2689 						PACKET_CAPTURE_MODE_DISABLE) {
2690 		adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE);
2691 		if (adapter) {
2692 			vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
2693 							   WLAN_OSIF_POWER_ID);
2694 			if (vdev) {
2695 				ucfg_pkt_capture_resume_mon_thread(vdev);
2696 				hdd_objmgr_put_vdev_by_user(
2697 					vdev, WLAN_OSIF_POWER_ID);
2698 			} else {
2699 				hdd_err("vdev is NULL");
2700 			}
2701 		}
2702 	}
2703 
2704 resume_ol_rx:
2705 	/* Resume tlshim Rx thread */
2706 	wlan_hdd_rx_thread_resume(hdd_ctx);
2707 	scheduler_resume();
2708 	hdd_ctx->is_scheduler_suspended = false;
2709 resume_tx:
2710 	hdd_resume_wlan();
2711 resume_all_components:
2712 	ucfg_pmo_resume_all_components(hdd_ctx->psoc, QDF_SYSTEM_SUSPEND);
2713 	hdd_unpause_ns(hdd_ctx);
2714 
2715 	return -ETIME;
2716 
2717 }
2718 
_wlan_hdd_cfg80211_suspend_wlan(struct wiphy * wiphy,struct cfg80211_wowlan * wow)2719 static int _wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
2720 					   struct cfg80211_wowlan *wow)
2721 {
2722 	void *hif_ctx;
2723 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2724 	qdf_runtime_lock_t *suspend_lock;
2725 	int errno;
2726 
2727 	if (!hdd_ctx) {
2728 		hdd_err_rl("hdd context is null");
2729 		return -ENODEV;
2730 	}
2731 
2732 	/* If Wifi is off, return success for system suspend */
2733 	if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2734 		hdd_debug("Driver Modules not Enabled ");
2735 		return 0;
2736 	}
2737 
2738 	errno = wlan_hdd_validate_context(hdd_ctx);
2739 	if (0 != errno) {
2740 		if (pld_is_low_power_mode(hdd_ctx->parent_dev))
2741 			hdd_debug("low power mode (Deep Sleep/Hibernate)");
2742 		else
2743 			return errno;
2744 	}
2745 
2746 	hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2747 	if (!hif_ctx)
2748 		return -EINVAL;
2749 
2750 	suspend_lock = &hdd_ctx->runtime_context.system_suspend;
2751 	errno = qdf_runtime_pm_prevent_suspend_sync(suspend_lock);
2752 	if (errno)
2753 		return errno;
2754 
2755 	errno = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
2756 	if (errno) {
2757 		qdf_runtime_pm_allow_suspend(suspend_lock);
2758 		return errno;
2759 	}
2760 
2761 	return errno;
2762 }
2763 
wlan_hdd_cfg80211_suspend_wlan(struct wiphy * wiphy,struct cfg80211_wowlan * wow)2764 int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
2765 				   struct cfg80211_wowlan *wow)
2766 {
2767 	struct osif_psoc_sync *psoc_sync;
2768 	int errno;
2769 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2770 
2771 	errno = wlan_hdd_validate_context(hdd_ctx);
2772 	if (0 != errno) {
2773 		if (pld_is_low_power_mode(hdd_ctx->parent_dev))
2774 			hdd_debug("low power mode (Deep Sleep/Hibernate)");
2775 		else
2776 			return errno;
2777 	}
2778 
2779 	/*
2780 	 * Flush the idle shutdown before ops start.This is done here to avoid
2781 	 * the deadlock as idle shutdown waits for the dsc ops
2782 	 * to complete.
2783 	 */
2784 	hdd_psoc_idle_timer_stop(hdd_ctx);
2785 
2786 	errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
2787 	if (errno)
2788 		return errno;
2789 
2790 	errno = _wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
2791 
2792 	osif_psoc_sync_op_stop(psoc_sync);
2793 
2794 	return errno;
2795 }
2796 
2797 /**
2798  * hdd_stop_dhcp_ind() - API to stop DHCP sequence
2799  * @link_info: Link  info pointer in HDD adapter
2800  * @mac: mac address
2801  *
2802  * Release the wakelock held for DHCP process and allow
2803  * the runtime pm to continue
2804  *
2805  * Return: None
2806  */
hdd_stop_dhcp_ind(struct wlan_hdd_link_info * link_info,uint8_t * mac)2807 static void hdd_stop_dhcp_ind(struct wlan_hdd_link_info *link_info,
2808 			      uint8_t *mac)
2809 {
2810 	struct hdd_adapter *adapter = link_info->adapter;
2811 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2812 
2813 	hdd_debug("DHCP stop indicated through power save");
2814 	sme_dhcp_stop_ind(hdd_ctx->mac_handle, adapter->device_mode,
2815 			  mac, link_info->vdev_id);
2816 	hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
2817 	qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect);
2818 }
2819 
2820 /**
2821  * hdd_start_dhcp_ind() - API to start DHCP sequence
2822  * @link_info: Link info pointer in HDD adapter
2823  * @mac: mac address
2824  *
2825  * Prevent APPS suspend and the runtime suspend during
2826  * DHCP sequence
2827  *
2828  * Return: None
2829  */
2830 static void
hdd_start_dhcp_ind(struct wlan_hdd_link_info * link_info,uint8_t * mac)2831 hdd_start_dhcp_ind(struct wlan_hdd_link_info *link_info, uint8_t *mac)
2832 {
2833 	struct hdd_adapter *adapter = link_info->adapter;
2834 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2835 
2836 	hdd_debug("DHCP start indicated through power save");
2837 	qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.connect);
2838 	hdd_prevent_suspend_timeout(HDD_WAKELOCK_TIMEOUT_CONNECT,
2839 				    WIFI_POWER_EVENT_WAKELOCK_DHCP);
2840 	sme_dhcp_start_ind(hdd_ctx->mac_handle, adapter->device_mode,
2841 			   mac, link_info->vdev_id);
2842 }
2843 
wlan_hdd_set_ps(struct wlan_hdd_link_info * link_info,uint8_t * mac,bool allow_power_save,int timeout)2844 static int wlan_hdd_set_ps(struct wlan_hdd_link_info *link_info,
2845 			   uint8_t *mac, bool allow_power_save, int timeout)
2846 {
2847 	int status;
2848 	struct hdd_adapter *adapter = link_info->adapter;
2849 
2850 	status = wlan_hdd_set_powersave(link_info, allow_power_save, timeout);
2851 
2852 	if (!hdd_cm_is_vdev_associated(link_info)) {
2853 		hdd_debug("vdev[%d] mode %d disconnected ignore dhcp protection",
2854 			  link_info->vdev_id, adapter->device_mode);
2855 		return status;
2856 	}
2857 
2858 	hdd_debug("vdev[%d] mode %d enable dhcp protection",
2859 		  link_info->vdev_id, adapter->device_mode);
2860 	allow_power_save ? hdd_stop_dhcp_ind(link_info, mac) :
2861 			   hdd_start_dhcp_ind(link_info, mac);
2862 
2863 	return status;
2864 }
2865 
2866 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
2867 #ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
wlan_hdd_set_mlo_ps(struct hdd_adapter * adapter,bool allow_power_save,int timeout,int link_id)2868 int wlan_hdd_set_mlo_ps(struct hdd_adapter *adapter,
2869 			bool allow_power_save, int timeout,
2870 			int link_id)
2871 {
2872 	struct wlan_hdd_link_info *link_info;
2873 	int status = -EINVAL;
2874 
2875 	hdd_adapter_for_each_active_link_info(adapter, link_info) {
2876 		if (link_id >= 0 &&
2877 		    wlan_vdev_get_link_id(link_info->vdev) != link_id)
2878 			continue;
2879 
2880 		status = wlan_hdd_set_ps(link_info,
2881 					 link_info->link_addr.bytes,
2882 					 allow_power_save, timeout);
2883 		if (status)
2884 			break;
2885 	}
2886 
2887 	return status;
2888 }
2889 #else
wlan_hdd_set_mlo_ps(struct hdd_adapter * adapter,bool allow_power_save,int timeout,int link_id)2890 int wlan_hdd_set_mlo_ps(struct hdd_adapter *adapter,
2891 			bool allow_power_save, int timeout,
2892 			int link_id)
2893 {
2894 	struct hdd_adapter *link_adapter;
2895 	struct hdd_mlo_adapter_info *mlo_adapter_info;
2896 	int i, status = -EINVAL;
2897 
2898 	mlo_adapter_info = &adapter->mlo_adapter_info;
2899 	for (i = 0; i < WLAN_MAX_MLD; i++) {
2900 		link_adapter = mlo_adapter_info->link_adapter[i];
2901 		if (!link_adapter)
2902 			continue;
2903 
2904 		if (link_id >= 0 &&
2905 		    wlan_vdev_get_link_id(link_adapter->deflink->vdev) !=
2906 		    link_id)
2907 			continue;
2908 
2909 		status = wlan_hdd_set_ps(link_adapter->deflink,
2910 					 link_adapter->mac_addr.bytes,
2911 					 allow_power_save, timeout);
2912 		if (status)
2913 			break;
2914 	}
2915 
2916 	if (i == WLAN_MAX_MLD && link_id >= 0)
2917 		hdd_err("No link adapter found for link id: %d", link_id);
2918 
2919 	return status;
2920 }
2921 #endif
2922 #endif
2923 
2924 /**
2925  * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
2926  * @wiphy: Pointer to wiphy
2927  * @dev: Pointer to network device
2928  * @allow_power_save: is wlan allowed to go into power save mode
2929  * @timeout: Timeout value in ms
2930  *
2931  * Return: 0 for success, non-zero for failure
2932  */
__wlan_hdd_cfg80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool allow_power_save,int timeout)2933 static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
2934 					      struct net_device *dev,
2935 					      bool allow_power_save,
2936 					      int timeout)
2937 {
2938 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2939 	struct hdd_context *hdd_ctx;
2940 	int status;
2941 	struct wlan_hdd_link_info *link_info = adapter->deflink;
2942 
2943 	hdd_enter();
2944 
2945 	if (timeout < 0) {
2946 		hdd_debug("User space timeout: %d; Enter full power or power save: %d",
2947 			  timeout, allow_power_save);
2948 		timeout = 0;
2949 	}
2950 
2951 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2952 		hdd_err("Command not allowed in FTM mode");
2953 		return -EINVAL;
2954 	}
2955 
2956 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
2957 		return -EINVAL;
2958 
2959 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2960 		   TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
2961 		   link_info->vdev_id, timeout);
2962 
2963 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2964 	status = wlan_hdd_validate_context(hdd_ctx);
2965 
2966 	if (0 != status)
2967 		return status;
2968 
2969 	if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2970 		hdd_debug("Driver Module not enabled return success");
2971 		return 0;
2972 	}
2973 
2974 	/* Flush any scheduled inet change notifier work
2975 	 * This is to make sure set power save request
2976 	 * sent to FW are serialized to avoid race condition
2977 	 */
2978 	flush_work(&adapter->ipv4_notifier_work);
2979 	hdd_adapter_flush_ipv6_notifier_work(adapter);
2980 
2981 	if (hdd_adapter_is_ml_adapter(adapter)) {
2982 		status = wlan_hdd_set_mlo_ps(adapter, allow_power_save,
2983 					     timeout, -1);
2984 		goto exit;
2985 	}
2986 
2987 	status = wlan_hdd_set_ps(link_info, adapter->mac_addr.bytes,
2988 				 allow_power_save, timeout);
2989 
2990 exit:
2991 	/* Cache the powersave state for success case */
2992 	if (!status)
2993 		adapter->allow_power_save = allow_power_save;
2994 
2995 	hdd_exit();
2996 	return status;
2997 }
2998 
wlan_hdd_cfg80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool allow_power_save,int timeout)2999 int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
3000 				     struct net_device *dev,
3001 				     bool allow_power_save,
3002 				     int timeout)
3003 {
3004 	int errno;
3005 	struct osif_vdev_sync *vdev_sync;
3006 
3007 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
3008 	if (errno)
3009 		return errno;
3010 
3011 	errno = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev, allow_power_save,
3012 						   timeout);
3013 
3014 	osif_vdev_sync_op_stop(vdev_sync);
3015 
3016 	return errno;
3017 }
3018 
3019 /**
3020  * __wlan_hdd_cfg80211_set_txpower() - set TX power
3021  * @wiphy: Pointer to wiphy
3022  * @wdev: Pointer to network device
3023  * @type: TX power setting type
3024  * @mbm: TX power in mBm
3025  *
3026  * Return: 0 for success, non-zero for failure
3027  */
__wlan_hdd_cfg80211_set_txpower(struct wiphy * wiphy,struct wireless_dev * wdev,enum nl80211_tx_power_setting type,int mbm)3028 static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
3029 					   struct wireless_dev *wdev,
3030 					   enum nl80211_tx_power_setting type,
3031 					   int mbm)
3032 {
3033 	struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
3034 	mac_handle_t mac_handle;
3035 	struct hdd_adapter *adapter;
3036 	struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
3037 	struct qdf_mac_addr selfmac;
3038 	QDF_STATUS status;
3039 	int errno;
3040 	int dbm;
3041 
3042 	hdd_enter();
3043 
3044 	if (!wdev) {
3045 		hdd_err("wdev is null, set tx power failed");
3046 		return -EIO;
3047 	}
3048 
3049 	adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev);
3050 
3051 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3052 		hdd_err("Command not allowed in FTM mode");
3053 		return -EINVAL;
3054 	}
3055 
3056 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3057 		   TRACE_CODE_HDD_CFG80211_SET_TXPOWER,
3058 		   NO_SESSION, type);
3059 
3060 	errno = wlan_hdd_validate_context(hdd_ctx);
3061 	if (errno)
3062 		return errno;
3063 
3064 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
3065 		return -EINVAL;
3066 
3067 	if (adapter->device_mode == QDF_SAP_MODE ||
3068 	    adapter->device_mode == QDF_P2P_GO_MODE) {
3069 		qdf_copy_macaddr(&bssid, &adapter->mac_addr);
3070 	} else {
3071 		struct hdd_station_ctx *sta_ctx =
3072 			WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
3073 
3074 		if (hdd_cm_is_vdev_associated(adapter->deflink))
3075 			qdf_copy_macaddr(&bssid, &sta_ctx->conn_info.bssid);
3076 	}
3077 
3078 	qdf_copy_macaddr(&selfmac, &adapter->mac_addr);
3079 
3080 	mac_handle = hdd_ctx->mac_handle;
3081 
3082 	dbm = MBM_TO_DBM(mbm);
3083 
3084 	/*
3085 	 * the original implementation of this function expected power
3086 	 * values in dBm instead of mBm. If the conversion from mBm to
3087 	 * dBm is zero, then assume dBm was passed.
3088 	 */
3089 	if (!dbm)
3090 		dbm = mbm;
3091 
3092 	status = ucfg_mlme_set_current_tx_power_level(hdd_ctx->psoc, dbm);
3093 	if (QDF_IS_STATUS_ERROR(status)) {
3094 		hdd_err("sme_cfg_set_int failed for tx power %d, %d",
3095 			dbm, status);
3096 		return -EIO;
3097 	}
3098 
3099 	hdd_debug("Set tx power level %d dbm", dbm);
3100 
3101 	switch (type) {
3102 	/* Automatically determine transmit power */
3103 	case NL80211_TX_POWER_AUTOMATIC:
3104 	case NL80211_TX_POWER_LIMITED:
3105 	/* Limit TX power by the mBm parameter */
3106 		status = sme_set_max_tx_power(mac_handle, bssid, selfmac, dbm);
3107 		if (QDF_IS_STATUS_ERROR(status)) {
3108 			hdd_err("Setting maximum tx power failed, %d", status);
3109 			return -EIO;
3110 		}
3111 		break;
3112 
3113 	case NL80211_TX_POWER_FIXED:    /* Fix TX power to the mBm parameter */
3114 		status = sme_set_tx_power(mac_handle, adapter->deflink->vdev_id,
3115 					  bssid, adapter->device_mode, dbm);
3116 		if (QDF_IS_STATUS_ERROR(status)) {
3117 			hdd_err("Setting tx power failed, %d", status);
3118 			return -EIO;
3119 		}
3120 		break;
3121 	default:
3122 		hdd_err("Invalid power setting type %d", type);
3123 		return -EIO;
3124 	}
3125 
3126 	hdd_exit();
3127 	return 0;
3128 }
3129 
wlan_hdd_cfg80211_set_txpower(struct wiphy * wiphy,struct wireless_dev * wdev,enum nl80211_tx_power_setting type,int mbm)3130 int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
3131 				  struct wireless_dev *wdev,
3132 				  enum nl80211_tx_power_setting type,
3133 				  int mbm)
3134 {
3135 	struct osif_psoc_sync *psoc_sync;
3136 	int errno;
3137 
3138 	errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
3139 	if (errno)
3140 		return errno;
3141 
3142 	errno = __wlan_hdd_cfg80211_set_txpower(wiphy, wdev, type, mbm);
3143 
3144 	osif_psoc_sync_op_stop(psoc_sync);
3145 
3146 	return errno;
3147 }
3148 
3149 #define WLAN_HDD_TX_POWER_CACHE_EXPIRY_TIME 350
3150 
3151 static QDF_STATUS
wlan_hdd_tx_power_request_needed(struct hdd_adapter * adapter)3152 wlan_hdd_tx_power_request_needed(struct hdd_adapter *adapter)
3153 {
3154 	uint32_t tx_pwr_cached_duration;
3155 
3156 	tx_pwr_cached_duration =
3157 			qdf_system_ticks_to_msecs(qdf_system_ticks()) -
3158 			adapter->tx_power.tx_pwr_cached_timestamp;
3159 
3160 	if (tx_pwr_cached_duration <= WLAN_HDD_TX_POWER_CACHE_EXPIRY_TIME)
3161 		return QDF_STATUS_E_ALREADY;
3162 
3163 	return QDF_STATUS_SUCCESS;
3164 }
3165 
wlan_hdd_get_tx_power(struct hdd_adapter * adapter,int * dbm)3166 static int wlan_hdd_get_tx_power(struct hdd_adapter *adapter, int *dbm)
3167 {
3168 	struct wlan_objmgr_vdev *vdev;
3169 	int ret;
3170 
3171 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
3172 					   WLAN_OSIF_POWER_ID);
3173 	if (!vdev) {
3174 		hdd_info("vdev is NULL");
3175 		return -EINVAL;
3176 	}
3177 
3178 	ret = wlan_cfg80211_mc_cp_stats_get_tx_power(vdev, dbm);
3179 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
3180 	hdd_debug("power: %d", *dbm);
3181 	return ret;
3182 }
3183 
3184 #ifdef FEATURE_ANI_LEVEL_REQUEST
hdd_get_ani_level_cb(struct wmi_host_ani_level_event * ani,uint8_t num,void * context)3185 static void hdd_get_ani_level_cb(struct wmi_host_ani_level_event *ani,
3186 				 uint8_t num, void *context)
3187 {
3188 	struct osif_request *request;
3189 	struct ani_priv *priv;
3190 	uint8_t min_recv_freqs = QDF_MIN(num, MAX_NUM_FREQS_FOR_ANI_LEVEL);
3191 
3192 	request = osif_request_get(context);
3193 	if (!request) {
3194 		hdd_err("Obsolete request");
3195 		return;
3196 	}
3197 
3198 	/* propagate response back to requesting thread */
3199 	priv = osif_request_priv(request);
3200 	priv->ani = qdf_mem_malloc(min_recv_freqs *
3201 				   sizeof(struct wmi_host_ani_level_event));
3202 	if (!priv->ani)
3203 		goto complete;
3204 
3205 	priv->num_freq = min_recv_freqs;
3206 	qdf_mem_copy(priv->ani, ani,
3207 		     min_recv_freqs * sizeof(struct wmi_host_ani_level_event));
3208 
3209 complete:
3210 	osif_request_complete(request);
3211 	osif_request_put(request);
3212 }
3213 
3214 /**
3215  * wlan_hdd_get_ani_level_dealloc() - Dealloc mem allocated in priv data
3216  * @priv: the priv data
3217  *
3218  * Return: None
3219  */
wlan_hdd_get_ani_level_dealloc(void * priv)3220 static void wlan_hdd_get_ani_level_dealloc(void *priv)
3221 {
3222 	struct ani_priv *ani = priv;
3223 
3224 	if (ani->ani)
3225 		qdf_mem_free(ani->ani);
3226 }
3227 
wlan_hdd_get_ani_level(struct hdd_adapter * adapter,struct wmi_host_ani_level_event * ani,uint32_t * parsed_freqs,uint8_t num_freqs)3228 QDF_STATUS wlan_hdd_get_ani_level(struct hdd_adapter *adapter,
3229 				  struct wmi_host_ani_level_event *ani,
3230 				  uint32_t *parsed_freqs,
3231 				  uint8_t num_freqs)
3232 {
3233 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
3234 	int ret;
3235 	QDF_STATUS status;
3236 	void *cookie;
3237 	struct osif_request *request;
3238 	struct ani_priv *priv;
3239 	static const struct osif_request_params params = {
3240 		.priv_size = sizeof(*priv),
3241 		.timeout_ms = 1000,
3242 		.dealloc = wlan_hdd_get_ani_level_dealloc,
3243 	};
3244 
3245 	if (!hdd_ctx) {
3246 		hdd_err("Invalid HDD context");
3247 		return QDF_STATUS_E_INVAL;
3248 	}
3249 
3250 	request = osif_request_alloc(&params);
3251 	if (!request) {
3252 		hdd_err("Request allocation failure");
3253 		return QDF_STATUS_E_NOMEM;
3254 	}
3255 	cookie = osif_request_cookie(request);
3256 
3257 	status = sme_get_ani_level(hdd_ctx->mac_handle, parsed_freqs,
3258 				   num_freqs, hdd_get_ani_level_cb, cookie);
3259 
3260 	if (QDF_IS_STATUS_ERROR(status)) {
3261 		hdd_err("Unable to retrieve ani level");
3262 		goto complete;
3263 	} else {
3264 		/* request was sent -- wait for the response */
3265 		ret = osif_request_wait_for_response(request);
3266 		if (ret) {
3267 			hdd_err("SME timed out while retrieving ANI level");
3268 			status = QDF_STATUS_E_TIMEOUT;
3269 			goto complete;
3270 		}
3271 	}
3272 
3273 	priv = osif_request_priv(request);
3274 
3275 	qdf_mem_copy(ani, priv->ani, sizeof(struct wmi_host_ani_level_event) *
3276 		     priv->num_freq);
3277 
3278 complete:
3279 	/*
3280 	 * either we never sent a request, we sent a request and
3281 	 * received a response or we sent a request and timed out.
3282 	 * regardless we are done with the request.
3283 	 */
3284 	osif_request_put(request);
3285 
3286 	hdd_exit();
3287 	return status;
3288 }
3289 #endif
3290 
3291 /**
3292  * __wlan_hdd_cfg80211_get_txpower() - get TX power
3293  * @wiphy: Pointer to wiphy
3294  * @wdev: Pointer to network device
3295  * @dbm: Pointer to TX power in dbm
3296  *
3297  * Return: 0 for success, non-zero for failure
3298  */
__wlan_hdd_cfg80211_get_txpower(struct wiphy * wiphy,struct wireless_dev * wdev,int * dbm)3299 static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
3300 				  struct wireless_dev *wdev,
3301 				  int *dbm)
3302 {
3303 
3304 	struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
3305 	struct net_device *ndev = wdev->netdev;
3306 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
3307 	QDF_STATUS status;
3308 	int ret;
3309 	static bool is_rate_limited;
3310 	struct wlan_objmgr_vdev *vdev;
3311 
3312 	hdd_enter_dev(ndev);
3313 
3314 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3315 		hdd_err("Command not allowed in FTM mode");
3316 		return -EINVAL;
3317 	}
3318 
3319 	*dbm = 0;
3320 
3321 	ret = wlan_hdd_validate_context(hdd_ctx);
3322 	if (ret)
3323 		return ret;
3324 
3325 	/* Validate adapter sessionId */
3326 	ret = wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id);
3327 	if (ret)
3328 		return ret;
3329 	switch (adapter->device_mode) {
3330 	case QDF_STA_MODE:
3331 	case QDF_P2P_CLIENT_MODE:
3332 		if (hdd_cm_is_vdev_roaming(adapter->deflink)) {
3333 			hdd_debug("Roaming is in progress, rej this req");
3334 			return -EINVAL;
3335 		}
3336 		if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
3337 			hdd_debug("Not associated");
3338 			return 0;
3339 		}
3340 		break;
3341 	case QDF_SAP_MODE:
3342 	case QDF_P2P_GO_MODE:
3343 		if (!test_bit(SOFTAP_BSS_STARTED,
3344 			      &adapter->deflink->link_flags)) {
3345 			hdd_debug("SAP is not started yet");
3346 			return 0;
3347 		}
3348 		break;
3349 	default:
3350 		hdd_debug_rl("Current interface is not supported for get tx_power");
3351 		return 0;
3352 	}
3353 
3354 	HDD_IS_RATE_LIMIT_REQ(is_rate_limited,
3355 			      hdd_ctx->config->nb_commands_interval);
3356 	if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED ||
3357 	    is_rate_limited) {
3358 		/* Send cached data to upperlayer*/
3359 		vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
3360 						   WLAN_OSIF_POWER_ID);
3361 		if (!vdev) {
3362 			hdd_err("vdev is NULL");
3363 			return -EINVAL;
3364 		}
3365 		ucfg_mc_cp_stats_get_tx_power(vdev, dbm);
3366 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
3367 		hdd_debug("Modules not enabled/rate limited, cached tx power = %d",
3368 			  *dbm);
3369 		return 0;
3370 	}
3371 
3372 	status = wlan_hdd_tx_power_request_needed(adapter);
3373 	if (status == QDF_STATUS_E_ALREADY) {
3374 		/* TX_POWER is sent by STATION_STATS by firmware and
3375 		 * is copied into the adapter. So, return cached value.
3376 		 */
3377 		*dbm = adapter->tx_power.tx_pwr;
3378 		hdd_nofl_debug("cached tx_power: %d", *dbm);
3379 		return 0;
3380 	}
3381 
3382 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3383 		   TRACE_CODE_HDD_CFG80211_GET_TXPOWER,
3384 		   adapter->deflink->vdev_id, adapter->device_mode);
3385 
3386 	return wlan_hdd_get_tx_power(adapter, dbm);
3387 }
3388 
wlan_hdd_cfg80211_get_txpower(struct wiphy * wiphy,struct wireless_dev * wdev,int * dbm)3389 int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
3390 					 struct wireless_dev *wdev,
3391 					 int *dbm)
3392 {
3393 	struct osif_psoc_sync *psoc_sync;
3394 	int errno;
3395 
3396 	errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
3397 	if (errno)
3398 		return errno;
3399 
3400 	errno = __wlan_hdd_cfg80211_get_txpower(wiphy, wdev, dbm);
3401 
3402 	osif_psoc_sync_op_stop(psoc_sync);
3403 
3404 	return errno;
3405 }
3406 
3407 /**
3408  * hdd_convert_opm_mode() - convert opm with equivalent wma opm
3409  * @opm_mode: Optimized power management mode
3410  *
3411  * Return: enum wma_sta_ps_scheme_cfg
3412  */
3413 static enum wma_sta_ps_scheme_cfg
hdd_convert_opm_mode(enum qca_wlan_vendor_opm_mode opm_mode)3414 hdd_convert_opm_mode(enum qca_wlan_vendor_opm_mode opm_mode)
3415 {
3416 	switch (opm_mode) {
3417 	case QCA_WLAN_VENDOR_OPM_MODE_DISABLE:
3418 		return WMA_STA_PS_OPM_CONSERVATIVE;
3419 	case QCA_WLAN_VENDOR_OPM_MODE_ENABLE:
3420 		return WMA_STA_PS_OPM_AGGRESSIVE;
3421 	case QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED:
3422 		return WMA_STA_PS_USER_DEF;
3423 	default:
3424 		hdd_err("Invalid opm_mode: %d", opm_mode);
3425 		return WMA_STA_PS_OPM_CONSERVATIVE;
3426 	}
3427 }
3428 
hdd_set_power_config(struct hdd_context * hddctx,struct hdd_adapter * adapter,enum qca_wlan_vendor_opm_mode * opm_mode)3429 int hdd_set_power_config(struct hdd_context *hddctx,
3430 			 struct hdd_adapter *adapter,
3431 			 enum qca_wlan_vendor_opm_mode *opm_mode)
3432 {
3433 	QDF_STATUS status;
3434 
3435 	if (adapter->device_mode != QDF_STA_MODE &&
3436 	    adapter->device_mode != QDF_P2P_CLIENT_MODE) {
3437 		hdd_info("Advanced power save only allowed in STA/P2P-Client modes:%d",
3438 			 adapter->device_mode);
3439 		return -EINVAL;
3440 	}
3441 
3442 	if (*opm_mode > QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED ||
3443 	    *opm_mode < QCA_WLAN_VENDOR_OPM_MODE_DISABLE) {
3444 		hdd_err("invalid power value: %d", *opm_mode);
3445 		return -EINVAL;
3446 	}
3447 
3448 	if (ucfg_pmo_get_max_ps_poll(hddctx->psoc)) {
3449 		hdd_info("Disable advanced power save since max ps poll is enabled");
3450 		*opm_mode = QCA_WLAN_VENDOR_OPM_MODE_DISABLE;
3451 	}
3452 
3453 	status = wma_set_power_config(adapter->deflink->vdev_id,
3454 				      hdd_convert_opm_mode(*opm_mode));
3455 	if (status != QDF_STATUS_SUCCESS) {
3456 		hdd_err("failed to configure power: %d", status);
3457 		return -EINVAL;
3458 	}
3459 
3460 	return 0;
3461 }
3462 
hdd_set_power_config_params(struct hdd_context * hddctx,struct hdd_adapter * adapter,uint16_t ps_ito,uint16_t spec_wake)3463 int hdd_set_power_config_params(struct hdd_context *hddctx,
3464 				struct hdd_adapter *adapter,
3465 				uint16_t ps_ito, uint16_t spec_wake)
3466 {
3467 	QDF_STATUS status;
3468 
3469 	status = wma_set_power_config_ito(adapter->deflink->vdev_id, ps_ito);
3470 	if (status != QDF_STATUS_SUCCESS) {
3471 		hdd_err("failed to configure power ito: %d", status);
3472 		return -EINVAL;
3473 	}
3474 
3475 	status = wma_set_power_config_spec_wake(adapter->deflink->vdev_id,
3476 						spec_wake);
3477 	if (status != QDF_STATUS_SUCCESS) {
3478 		hdd_err("failed to configure power spec wake: %d", status);
3479 		return -EINVAL;
3480 	}
3481 
3482 	return 0;
3483 }
3484 
3485 #ifdef WLAN_SUSPEND_RESUME_TEST
3486 static struct net_device *g_dev;
3487 static struct wiphy *g_wiphy;
3488 static enum wow_resume_trigger g_resume_trigger;
3489 
3490 #define HDD_FA_SUSPENDED_BIT (0)
3491 static unsigned long fake_apps_state;
3492 
3493 /**
3494  * __hdd_wlan_fake_apps_resume() - The core logic for
3495  *	hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(),
3496  *	which is only need for non-irq resume
3497  * @wiphy: the kernel wiphy struct for the device being resumed
3498  * @dev: the kernel net_device struct for the device being resumed
3499  *
3500  * Return: none, calls QDF_BUG() on failure
3501  */
__hdd_wlan_fake_apps_resume(struct wiphy * wiphy,struct net_device * dev)3502 static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy,
3503 					struct net_device *dev)
3504 {
3505 	struct hif_opaque_softc *hif_ctx;
3506 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
3507 	qdf_device_t qdf_dev;
3508 
3509 	if (wlan_hdd_validate_context(hdd_ctx))
3510 		return;
3511 
3512 	if (!hdd_ctx->config->is_unit_test_framework_enabled) {
3513 		hdd_warn_rl("UT framework is disabled");
3514 		return;
3515 	}
3516 
3517 	hdd_info("Unit-test resume WLAN");
3518 
3519 	qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
3520 	if (!qdf_dev) {
3521 		QDF_BUG(0);
3522 		return;
3523 	}
3524 
3525 	hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
3526 	if (!hif_ctx)
3527 		return;
3528 
3529 	if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
3530 		hdd_alert("Not unit-test suspended; Nothing to do");
3531 		return;
3532 	}
3533 
3534 	/* simulate kernel disable irqs */
3535 	QDF_BUG(!hif_apps_wake_irq_disable(hif_ctx));
3536 
3537 	QDF_BUG(!wlan_hdd_bus_resume_noirq());
3538 
3539 	/* simulate kernel enable irqs */
3540 	QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
3541 
3542 	QDF_BUG(!wlan_hdd_bus_resume(QDF_UNIT_TEST_WOW_SUSPEND));
3543 
3544 	QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
3545 
3546 	if (g_resume_trigger == WOW_RESUME_TRIGGER_HTC_WAKEUP)
3547 		hif_vote_link_down(hif_ctx);
3548 
3549 	dev->watchdog_timeo = HDD_TX_TIMEOUT;
3550 
3551 	hdd_alert("Unit-test resume succeeded");
3552 
3553 	hdd_info("allow rtpm wow for wow unit test");
3554 	qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.wow_unit_test);
3555 }
3556 
3557 /**
3558  * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming
3559  *	from unit-test initiated suspend from irq wakeup signal
3560  *
3561  * Resume wlan after getting very 1st CE interrupt from target
3562  *
3563  * Return: none
3564  */
hdd_wlan_fake_apps_resume_irq_callback(void)3565 static void hdd_wlan_fake_apps_resume_irq_callback(void)
3566 {
3567 	hdd_info("Trigger unit-test resume WLAN");
3568 
3569 	QDF_BUG(g_wiphy);
3570 	QDF_BUG(g_dev);
3571 	__hdd_wlan_fake_apps_resume(g_wiphy, g_dev);
3572 	g_wiphy = NULL;
3573 	g_dev = NULL;
3574 }
3575 
hdd_wlan_fake_apps_suspend(struct wiphy * wiphy,struct net_device * dev,enum wow_interface_pause pause_setting,enum wow_resume_trigger resume_setting)3576 int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev,
3577 			       enum wow_interface_pause pause_setting,
3578 			       enum wow_resume_trigger resume_setting)
3579 {
3580 	int errno;
3581 	qdf_device_t qdf_dev;
3582 	struct hif_opaque_softc *hif_ctx;
3583 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
3584 	struct wow_enable_params wow_params = {
3585 		.is_unit_test = true,
3586 		.interface_pause = pause_setting,
3587 		.resume_trigger = resume_setting
3588 	};
3589 
3590 	if (wlan_hdd_validate_context(hdd_ctx))
3591 		return -EINVAL;
3592 
3593 	if (!hdd_ctx->config->is_unit_test_framework_enabled) {
3594 		hdd_warn_rl("UT framework is disabled");
3595 		return -EINVAL;
3596 	}
3597 
3598 	hdd_info("Unit-test suspend WLAN");
3599 
3600 	if (pause_setting < WOW_INTERFACE_PAUSE_DEFAULT ||
3601 	    pause_setting >= WOW_INTERFACE_PAUSE_COUNT) {
3602 		hdd_err_rl("Invalid interface pause %d (expected range [0, 2])",
3603 			   pause_setting);
3604 		return -EINVAL;
3605 	}
3606 
3607 	if (resume_setting < WOW_RESUME_TRIGGER_DEFAULT ||
3608 	    resume_setting >= WOW_RESUME_TRIGGER_COUNT) {
3609 		hdd_err_rl("Invalid resume trigger %d (expected range [0, 2])",
3610 			   resume_setting);
3611 		return -EINVAL;
3612 	}
3613 
3614 	qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
3615 	if (!qdf_dev)
3616 		return -EINVAL;
3617 
3618 	hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
3619 	if (!hif_ctx)
3620 		return -EINVAL;
3621 
3622 	if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
3623 		hdd_alert("Already unit-test suspended; Nothing to do");
3624 		return 0;
3625 	}
3626 
3627 	hdd_info("prevent rtpm wow for wow unit test");
3628 	qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.wow_unit_test);
3629 
3630 	/* pci link is needed to wakeup from HTC wakeup trigger */
3631 	if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP)
3632 		hif_vote_link_up(hif_ctx);
3633 
3634 	errno = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL);
3635 	if (errno)
3636 		goto link_down;
3637 
3638 	errno = wlan_hdd_unit_test_bus_suspend(wow_params);
3639 	if (errno)
3640 		goto cfg80211_resume;
3641 
3642 	/* simulate kernel disabling irqs */
3643 	errno = hif_apps_irqs_disable(hif_ctx);
3644 	if (errno)
3645 		goto bus_resume;
3646 
3647 	errno = wlan_hdd_bus_suspend_noirq();
3648 	if (errno)
3649 		goto enable_irqs;
3650 
3651 	/* pass wiphy/dev to callback via global variables */
3652 	g_wiphy = wiphy;
3653 	g_dev = dev;
3654 	g_resume_trigger = resume_setting;
3655 	hif_ut_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback);
3656 
3657 	/* re-enable wake irq */
3658 	errno = hif_apps_wake_irq_enable(hif_ctx);
3659 	if (errno)
3660 		goto fake_apps_resume;
3661 
3662 	/*
3663 	 * Tell the kernel not to worry if TX queues aren't moving. This is
3664 	 * expected since we are suspending the wifi hardware, but not APPS
3665 	 */
3666 	dev->watchdog_timeo = INT_MAX;
3667 
3668 	hdd_alert("Unit-test suspend succeeded");
3669 
3670 	return 0;
3671 
3672 fake_apps_resume:
3673 	hif_ut_apps_resume(hif_ctx);
3674 
3675 enable_irqs:
3676 	QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
3677 
3678 bus_resume:
3679 	QDF_BUG(!wlan_hdd_bus_resume(QDF_UNIT_TEST_WOW_SUSPEND));
3680 
3681 cfg80211_resume:
3682 	QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
3683 
3684 link_down:
3685 	if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP)
3686 		hif_vote_link_down(hif_ctx);
3687 
3688 	clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state);
3689 	hdd_err("Unit-test suspend failed: %d", errno);
3690 
3691 	hdd_info("allow rtpm wow for wow unit test");
3692 	qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.wow_unit_test);
3693 
3694 	return errno;
3695 }
3696 
hdd_wlan_fake_apps_resume(struct wiphy * wiphy,struct net_device * dev)3697 int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev)
3698 {
3699 	struct hif_opaque_softc *hif_ctx;
3700 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
3701 
3702 	if (wlan_hdd_validate_context(hdd_ctx))
3703 		return -EINVAL;
3704 
3705 	if (!hdd_ctx->config->is_unit_test_framework_enabled) {
3706 		hdd_warn_rl("UT framework is disabled");
3707 		return -EINVAL;
3708 	}
3709 
3710 	hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
3711 	if (!hif_ctx)
3712 		return -EINVAL;
3713 
3714 	hif_ut_apps_resume(hif_ctx);
3715 	__hdd_wlan_fake_apps_resume(wiphy, dev);
3716 
3717 	return 0;
3718 }
3719 #endif
3720