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