blob: bbca604ae850a1c7d860d2a149a49862f7ae0e9d [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Prashanth Bhatta9e143052015-12-04 11:56:47 -08002 * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_power.c
30 *
31 * WLAN power management functions
32 *
33 */
34
35/* Include files */
36
37#include <linux/pm.h>
38#include <linux/wait.h>
39#include <linux/cpu.h>
40#include <wlan_hdd_includes.h>
41#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK)
42#include <linux/wakelock.h>
43#endif
Anurag Chouhan6d760662016-02-20 16:05:43 +053044#include "qdf_types.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080045#include "sme_api.h"
46#include <cds_api.h>
47#include <cds_sched.h>
48#include <mac_init_api.h>
49#include <wlan_qct_sys.h>
50#include <wlan_hdd_main.h>
51#include <wlan_hdd_assoc.h>
52#include <wlan_nlink_srv.h>
53#include <wlan_hdd_misc.h>
54#include <wlan_hdd_power.h>
Jeff Johnsonc8d0c252016-10-05 16:19:50 -070055#include <wlan_hdd_host_offload.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080056#include <dbglog_host.h>
57#include <wlan_hdd_trace.h>
Masti, Narayanraddi3e26de62016-08-19 14:33:22 +053058#include <wlan_hdd_p2p.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059
60#include <linux/semaphore.h>
61#include <wlan_hdd_hostapd.h>
62#include "cfg_api.h"
63
64#include <linux/inetdevice.h>
65#include <wlan_hdd_cfg.h>
Sandeep Puligillae390be52016-02-08 17:07:05 -080066#include <wlan_hdd_scan.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080067#include <wlan_hdd_cfg80211.h>
68#include <net/addrconf.h>
69#include <wlan_hdd_ipa.h>
Jeff Johnson2b0a7b82016-05-18 15:08:02 -070070#include <wlan_hdd_lpass.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071
72#include <wma_types.h>
73#include "hif.h"
74#include "sme_power_save_api.h"
Chandrasekaran, Manishekar0d814c72015-11-05 10:42:48 +053075#include "cds_concurrency.h"
Dhanashri Atreb08959a2016-03-01 17:28:03 -080076#include "cdp_txrx_flow_ctrl_v2.h"
Yuanyuan Liu13738502016-04-06 17:41:37 -070077#include "pld_common.h"
Rajeev Kumar9bb2e852016-09-24 12:29:25 -070078#include "wlan_hdd_driver_ops.h"
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +053079#include <wlan_logging_sock_svc.h>
Krunal Sonid32c6bc2016-10-18 18:00:21 -070080#include "scheduler_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080081
82/* Preprocessor definitions and constants */
Yue Ma4ea4f052015-10-27 12:25:27 -070083#define HDD_SSR_BRING_UP_TIME 30000
Sreelakshmi Konamki22528532016-09-06 16:34:50 +053084#define HDD_WAKE_LOCK_RESUME_DURATION 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080085
86/* Type declarations */
87
Abhishek Singhbaea27d2016-04-27 13:29:30 +053088#ifdef FEATURE_WLAN_DIAG_SUPPORT
89/**
90 * hdd_wlan_suspend_resume_event()- send suspend/resume state
91 * @state: suspend/resume state
92 *
93 * This Function send send suspend resume state diag event
94 *
95 * Return: void.
96 */
97void hdd_wlan_suspend_resume_event(uint8_t state)
98{
99 WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend);
100 qdf_mem_zero(&suspend_state, sizeof(suspend_state));
101
102 suspend_state.state = state;
103 WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
104}
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530105
106/**
107 * hdd_wlan_offload_event()- send offloads event
108 * @type: offload type
109 * @state: enabled or disabled
110 *
111 * This Function send offloads enable/disable diag event
112 *
113 * Return: void.
114 */
115
116void hdd_wlan_offload_event(uint8_t type, uint8_t state)
117{
118 WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req);
119 qdf_mem_zero(&host_offload, sizeof(host_offload));
120
121 host_offload.offload_type = type;
122 host_offload.state = state;
123
124 WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ);
125}
Abhishek Singhbaea27d2016-04-27 13:29:30 +0530126#endif
127
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800128/* Function and variables declarations */
129
130extern struct notifier_block hdd_netdev_notifier;
131
132static struct timer_list ssr_timer;
133static bool ssr_timer_started;
134/**
135 * hdd_conf_gtk_offload() - Configure GTK offload
136 * @pAdapter: pointer to the adapter
137 * @fenable: flag set to enable (1) or disable (0) GTK offload
138 *
139 * Central function to enable or disable GTK offload.
140 *
141 * Return: nothing
142 */
143#ifdef WLAN_FEATURE_GTK_OFFLOAD
144static void hdd_conf_gtk_offload(hdd_adapter_t *pAdapter, bool fenable)
145{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530146 QDF_STATUS ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800147 tSirGtkOffloadParams hddGtkOffloadReqParams;
148 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
149
150 if (fenable) {
151 if ((eConnectionState_Associated ==
152 pHddStaCtx->conn_info.connState)
153 && (GTK_OFFLOAD_ENABLE ==
154 pHddStaCtx->gtkOffloadReqParams.ulFlags)) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530155 qdf_mem_copy(&hddGtkOffloadReqParams,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800156 &pHddStaCtx->gtkOffloadReqParams,
157 sizeof(tSirGtkOffloadParams));
158
159 ret = sme_set_gtk_offload(WLAN_HDD_GET_HAL_CTX(pAdapter),
160 &hddGtkOffloadReqParams,
161 pAdapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530162 if (QDF_STATUS_SUCCESS != ret) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700163 hdd_err("sme_set_gtk_offload failed, returned %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800164 return;
165 }
166
Jeff Johnsonc3273322016-07-06 15:28:17 -0700167 hdd_notice("sme_set_gtk_offload successfull");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800168 }
169
170 } else {
171 if ((eConnectionState_Associated ==
172 pHddStaCtx->conn_info.connState)
Anurag Chouhanc5548422016-02-24 18:33:27 +0530173 && (qdf_is_macaddr_equal(&pHddStaCtx->gtkOffloadReqParams.bssid,
Srinivas Girigowda2213b1d2015-11-20 17:10:11 -0800174 &pHddStaCtx->conn_info.bssId))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800175 && (GTK_OFFLOAD_ENABLE ==
176 pHddStaCtx->gtkOffloadReqParams.ulFlags)) {
177
178 /* Host driver has previously offloaded GTK rekey */
179 ret = sme_get_gtk_offload
180 (WLAN_HDD_GET_HAL_CTX(pAdapter),
181 wlan_hdd_cfg80211_update_replay_counter_callback,
182 pAdapter, pAdapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530183 if (QDF_STATUS_SUCCESS != ret) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700184 hdd_err("sme_get_gtk_offload failed, returned %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185 return;
186 } else {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700187 hdd_notice("sme_get_gtk_offload successful");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800188
189 /* Sending GTK offload dissable */
190 memcpy(&hddGtkOffloadReqParams,
191 &pHddStaCtx->gtkOffloadReqParams,
192 sizeof(tSirGtkOffloadParams));
193 hddGtkOffloadReqParams.ulFlags =
194 GTK_OFFLOAD_DISABLE;
195 ret =
196 sme_set_gtk_offload(WLAN_HDD_GET_HAL_CTX
197 (pAdapter),
198 &hddGtkOffloadReqParams,
199 pAdapter->sessionId);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530200 if (QDF_STATUS_SUCCESS != ret) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700201 hdd_err("failed to dissable GTK offload, returned %d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800202 return;
203 }
Jeff Johnsonc3273322016-07-06 15:28:17 -0700204 hdd_notice("successfully dissabled GTK offload request to HAL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800205 }
206 }
207 }
208 return;
209}
210#else /* WLAN_FEATURE_GTK_OFFLOAD */
211static void hdd_conf_gtk_offload(hdd_adapter_t *pAdapter, bool fenable)
212{
213}
214#endif /*WLAN_FEATURE_GTK_OFFLOAD */
215
216#ifdef WLAN_NS_OFFLOAD
217/**
218 * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function
219 * @nb: notifier block that was registered with the kernel
220 * @data: (unused) generic data that was registered with the kernel
221 * @arg: (unused) generic argument that was registered with the kernel
222 *
223 * This is a callback function that is registered with the kernel via
224 * register_inet6addr_notifier() which allows the driver to be
225 * notified when there is an IPv6 address change.
226 *
227 * Return: NOTIFY_DONE to indicate we don't care what happens with
228 * other callbacks
229 */
230static int __wlan_hdd_ipv6_changed(struct notifier_block *nb,
231 unsigned long data, void *arg)
232{
233 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
234 struct net_device *ndev = ifa->idev->dev;
235 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
236 hdd_context_t *pHddCtx;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700237 hdd_station_ctx_t *sta_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800238 int status;
239
Jeff Johnson158c8d02016-10-31 13:11:48 -0700240 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530241
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800242 if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700243 hdd_err("Adapter context is invalid %p", pAdapter);
Jeff Johnson158c8d02016-10-31 13:11:48 -0700244 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800245 }
246
247 if ((pAdapter->dev == ndev) &&
Jeff Johnson158c8d02016-10-31 13:11:48 -0700248 (pAdapter->device_mode == QDF_STA_MODE ||
249 pAdapter->device_mode == QDF_P2P_CLIENT_MODE ||
250 pAdapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800251 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
252 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530253 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800254 return NOTIFY_DONE;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700255 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Abhishek Singhca408032016-09-13 15:26:12 +0530256 if (eConnectionState_Associated ==
Jeff Johnson158c8d02016-10-31 13:11:48 -0700257 sta_ctx->conn_info.connState) {
258 hdd_info("invoking sme_dhcp_done_ind");
Abhishek Singhca408032016-09-13 15:26:12 +0530259 sme_dhcp_done_ind(pHddCtx->hHal,
Jeff Johnson158c8d02016-10-31 13:11:48 -0700260 pAdapter->sessionId);
261 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800262 schedule_work(&pAdapter->ipv6NotifierWorkQueue);
263 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530264 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800265 return NOTIFY_DONE;
266}
267
268/**
269 * wlan_hdd_ipv6_changed() - IPv6 change notifier callback
270 * @nb: pointer to notifier block
271 * @data: data
272 * @arg: arg
273 *
274 * This is the IPv6 notifier callback function gets invoked
275 * if any change in IP and then invoke the function @__wlan_hdd_ipv6_changed
276 * to reconfigure the offload parameters.
277 *
278 * Return: 0 on success, error number otherwise.
279 */
280int wlan_hdd_ipv6_changed(struct notifier_block *nb,
281 unsigned long data, void *arg)
282{
283 int ret;
284
285 cds_ssr_protect(__func__);
286 ret = __wlan_hdd_ipv6_changed(nb, data, arg);
287 cds_ssr_unprotect(__func__);
288
289 return ret;
290}
291
292/**
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530293 * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses
294 * @idev: pointer to net device
295 * @ipv6addr: destination array to fill IPv6 addresses
296 * @ipv6addr_type: IPv6 Address type
297 * @count: number of IPv6 addresses
298 *
299 * This is the IPv6 utility function to populate unicast addresses.
300 *
301 * Return: 0 on success, error number otherwise.
302 */
303static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
304 uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN],
305 uint8_t *ipv6addr_type, uint32_t *count)
306{
307 struct inet6_ifaddr *ifa;
308 struct list_head *p;
309 uint32_t scope;
310
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700311 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530312 list_for_each(p, &idev->addr_list) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700313 if (*count >= SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
314 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530315 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700316 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530317 ifa = list_entry(p, struct inet6_ifaddr, if_list);
318 if (ifa->flags & IFA_F_DADFAILED)
319 continue;
320 scope = ipv6_addr_src_scope(&ifa->addr);
321 switch (scope) {
322 case IPV6_ADDR_SCOPE_GLOBAL:
323 case IPV6_ADDR_SCOPE_LINKLOCAL:
324 qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
325 sizeof(ifa->addr.s6_addr));
326 ipv6addr_type[*count] = SIR_IPV6_ADDR_UC_TYPE;
327 hdd_info("Index %d scope = %s UC-Address: %pI6",
328 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
329 "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
330 *count += 1;
331 break;
332 default:
333 hdd_err("The Scope %d is not supported", scope);
334 }
335 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700336
337 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530338 return 0;
339}
340
341/**
342 * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses
343 * @idev: pointer to net device
344 * @ipv6addr: destination array to fill IPv6 addresses
345 * @ipv6addr_type: IPv6 Address type
346 * @count: number of IPv6 addresses
347 *
348 * This is the IPv6 utility function to populate anycast addresses.
349 *
350 * Return: 0 on success, error number otherwise.
351 */
352static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
353 uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN],
354 uint8_t *ipv6addr_type, uint32_t *count)
355{
356 struct ifacaddr6 *ifaca;
357 uint32_t scope;
358
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700359 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530360 for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700361 if (*count >= SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
362 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530363 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700364 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530365 /* For anycast addr no DAD */
366 scope = ipv6_addr_src_scope(&ifaca->aca_addr);
367 switch (scope) {
368 case IPV6_ADDR_SCOPE_GLOBAL:
369 case IPV6_ADDR_SCOPE_LINKLOCAL:
370 qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
371 sizeof(ifaca->aca_addr));
372 ipv6addr_type[*count] = SIR_IPV6_ADDR_AC_TYPE;
373 hdd_info("Index %d scope = %s AC-Address: %pI6",
374 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
375 "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
376 *count += 1;
377 break;
378 default:
379 hdd_err("The Scope %d is not supported", scope);
380 }
381 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700382
383 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530384 return 0;
385}
386
387/**
Dustin Brown2444ee62016-09-06 17:20:36 -0700388 * hdd_disable_ns_offload() - Disables IPv6 NS offload
389 * @adapter: ponter to the adapter
390 *
391 * Return: nothing
392 */
393static void hdd_disable_ns_offload(hdd_adapter_t *adapter)
394{
395 tSirHostOffloadReq offloadReq;
396 QDF_STATUS status;
397
398 qdf_mem_zero((void *)&offloadReq, sizeof(tSirHostOffloadReq));
399 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_DISABLE);
400 offloadReq.enableOrDisable = SIR_OFFLOAD_DISABLE;
401 offloadReq.offloadType = SIR_IPV6_NS_OFFLOAD;
402 status = sme_set_host_offload(
403 WLAN_HDD_GET_HAL_CTX(adapter),
404 adapter->sessionId, &offloadReq);
405
406 if (QDF_STATUS_SUCCESS != status)
407 hdd_err("Failed to disable NS Offload");
408}
409
410/**
411 * hdd_enable_ns_offload() - Enables IPv6 NS offload
412 * @adapter: ponter to the adapter
413 *
414 * Return: nothing
415 */
416static void hdd_enable_ns_offload(hdd_adapter_t *adapter)
417{
418 struct inet6_dev *in6_dev;
419 uint8_t ipv6_addr[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]
420 [SIR_MAC_IPV6_ADDR_LEN] = { {0,} };
421 uint8_t ipv6_addr_type[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] = { 0 };
422 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
423 tSirHostOffloadReq offloadReq;
424 QDF_STATUS status;
425 uint32_t count = 0;
426 int err, i;
427
428 in6_dev = __in6_dev_get(adapter->dev);
429 if (NULL == in6_dev) {
430 hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
431 return;
432 }
433
434 /* Unicast Addresses */
435 err = hdd_fill_ipv6_uc_addr(in6_dev, ipv6_addr, ipv6_addr_type, &count);
436 if (err) {
437 hdd_disable_ns_offload(adapter);
438 hdd_notice("Reached max supported addresses and not enabling "
439 "NS offload");
440 return;
441 }
442
443 /* Anycast Addresses */
444 err = hdd_fill_ipv6_ac_addr(in6_dev, ipv6_addr, ipv6_addr_type, &count);
445 if (err) {
446 hdd_disable_ns_offload(adapter);
447 hdd_notice("Reached max supported addresses and not enabling "
448 "NS offload");
449 return;
450 }
451
452 qdf_mem_zero(&offloadReq, sizeof(offloadReq));
453 for (i = 0; i < count; i++) {
454 /* Filling up the request structure
455 * Filling the selfIPv6Addr with solicited address
456 * A Solicited-Node multicast address is created by
457 * taking the last 24 bits of a unicast or anycast
458 * address and appending them to the prefix
459 *
460 * FF02:0000:0000:0000:0000:0001:FFXX:XXXX
461 *
462 * here XX is the unicast/anycast bits
463 */
464 offloadReq.nsOffloadInfo.selfIPv6Addr[i][0] = 0xFF;
465 offloadReq.nsOffloadInfo.selfIPv6Addr[i][1] = 0x02;
466 offloadReq.nsOffloadInfo.selfIPv6Addr[i][11] = 0x01;
467 offloadReq.nsOffloadInfo.selfIPv6Addr[i][12] = 0xFF;
468 offloadReq.nsOffloadInfo.selfIPv6Addr[i][13] =
469 ipv6_addr[i][13];
470 offloadReq.nsOffloadInfo.selfIPv6Addr[i][14] =
471 ipv6_addr[i][14];
472 offloadReq.nsOffloadInfo.selfIPv6Addr[i][15] =
473 ipv6_addr[i][15];
474 offloadReq.nsOffloadInfo.slotIdx = i;
475 qdf_mem_copy(&offloadReq.nsOffloadInfo.targetIPv6Addr[i],
476 &ipv6_addr[i][0], SIR_MAC_IPV6_ADDR_LEN);
477
478 offloadReq.nsOffloadInfo.targetIPv6AddrValid[i] =
479 SIR_IPV6_ADDR_VALID;
480 offloadReq.nsOffloadInfo.target_ipv6_addr_ac_type[i] =
481 ipv6_addr_type[i];
482
483 qdf_mem_copy(&offloadReq.params.hostIpv6Addr,
484 &offloadReq.nsOffloadInfo.targetIPv6Addr[i],
485 SIR_MAC_IPV6_ADDR_LEN);
486
487 hdd_info("Setting NSOffload with solicitedIp: "
488 "%pI6, targetIp: %pI6, Index %d",
489 &offloadReq.nsOffloadInfo.selfIPv6Addr[i],
490 &offloadReq.nsOffloadInfo.targetIPv6Addr[i], i);
491 }
492
493 hdd_info("configuredMcastBcastFilter: %d",
494 hdd_ctx->configuredMcastBcastFilter);
495 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
496 offloadReq.offloadType = SIR_IPV6_NS_OFFLOAD;
497 offloadReq.enableOrDisable = SIR_OFFLOAD_ENABLE;
498 qdf_copy_macaddr(&offloadReq.nsOffloadInfo.self_macaddr,
499 &adapter->macAddressCurrent);
500
501 /* set number of ns offload address count */
502 offloadReq.num_ns_offload_count = count;
503
504 /* Configure the Firmware with this */
505 status = sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(adapter),
506 adapter->sessionId, &offloadReq);
507 if (QDF_STATUS_SUCCESS != status) {
508 hdd_err("Failed to enable HostOffload feature with status: %d",
509 status);
510 }
511}
512
513/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800514 * hdd_conf_ns_offload() - Configure NS offload
Dustin Brown2444ee62016-09-06 17:20:36 -0700515 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800516 * @fenable: flag to enable or disable
517 * 0 - disable
518 * 1 - enable
519 *
520 * Return: nothing
521 */
Dustin Brownd8279d22016-09-07 14:52:57 -0700522void hdd_conf_ns_offload(hdd_adapter_t *adapter, bool fenable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800523{
Dustin Brown2444ee62016-09-06 17:20:36 -0700524 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800525
526 ENTER();
Jeff Johnsonc3273322016-07-06 15:28:17 -0700527 hdd_notice(" fenable = %d", fenable);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800528
Dustin Brown2444ee62016-09-06 17:20:36 -0700529 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800530
531 /* In SAP/P2PGo mode, ARP/NS offload feature capability
532 * is controlled by one bit.
533 */
534
Dustin Brown2444ee62016-09-06 17:20:36 -0700535 if ((QDF_SAP_MODE == adapter->device_mode ||
536 QDF_P2P_GO_MODE == adapter->device_mode) &&
537 !hdd_ctx->ap_arpns_support) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700538 hdd_notice("NS Offload is not supported in SAP/P2PGO mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800539 return;
540 }
541
Dustin Brown2444ee62016-09-06 17:20:36 -0700542 if (fenable)
543 hdd_enable_ns_offload(adapter);
544 else
545 hdd_disable_ns_offload(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800546
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800547 EXIT();
548 return;
549}
550
551/**
552 * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function
553 * @work: registered work item
554 *
555 * This function performs the work initially trigged by a callback
556 * from the IPv6 netdev notifier. Since this means there has been a
557 * change in IPv6 state for the interface, the NS offload is
558 * reconfigured.
559 *
560 * Return: None
561 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700562static void __hdd_ipv6_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800563{
564 hdd_adapter_t *pAdapter =
565 container_of(work, hdd_adapter_t, ipv6NotifierWorkQueue);
566 hdd_context_t *pHddCtx;
567 int status;
Deepak Dhamdheref16015f2016-06-01 14:28:09 -0700568 bool ndi_connected = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800569
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530570 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800571
572 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
573 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530574 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800575 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800576
577 if (!pHddCtx->config->active_mode_offload) {
578 hdd_err("Active mode offload is disabled");
579 return;
580 }
581
582 if (false == pHddCtx->sus_res_mcastbcast_filter_valid) {
583 pHddCtx->sus_res_mcastbcast_filter =
584 pHddCtx->configuredMcastBcastFilter;
585 pHddCtx->sus_res_mcastbcast_filter_valid = true;
586 }
587
Deepak Dhamdheref16015f2016-06-01 14:28:09 -0700588 /* check if the device is in NAN data mode */
589 if (WLAN_HDD_IS_NDI(pAdapter))
590 ndi_connected = WLAN_HDD_IS_NDI_CONNECTED(pAdapter);
591
592 if (eConnectionState_Associated ==
593 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState ||
594 ndi_connected)
Sravan Kumar Kairamfece87f2016-07-26 14:58:28 +0530595 if (pHddCtx->config->fhostNSOffload &&
596 pHddCtx->ns_offload_enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800597 hdd_conf_ns_offload(pAdapter, true);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530598 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800599}
600
601/**
602 * hdd_ipv6_notifier_work_queue() - IP V6 change notifier work handler
603 * @work: Pointer to work context
604 *
605 * Return: none
606 */
607void hdd_ipv6_notifier_work_queue(struct work_struct *work)
608{
609 cds_ssr_protect(__func__);
610 __hdd_ipv6_notifier_work_queue(work);
611 cds_ssr_unprotect(__func__);
612}
613
614/**
615 * hdd_conf_hostoffload() - Central function to configure the supported offloads
616 * @pAdapter: pointer to the adapter
617 * @fenable: flag set to enable (1) or disable (0)
618 *
619 * Central function to configure the supported offloads either
620 * enable or disable them.
621 *
622 * Return: nothing
623 */
624void hdd_conf_hostoffload(hdd_adapter_t *pAdapter, bool fenable)
625{
626 hdd_context_t *pHddCtx;
627
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530628 ENTER();
629
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800630 hdd_info("Configuring offloads with flag: %d", fenable);
631
632 /* Get the HDD context. */
633 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
634
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800635 if (((QDF_STA_MODE != pAdapter->device_mode) &&
636 (QDF_P2P_CLIENT_MODE != pAdapter->device_mode))) {
Rajeev Kumar30cb6762016-07-28 20:01:15 -0700637 hdd_info("Offloads not supported in mode %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800638 pAdapter->device_mode);
639 return;
640 }
641
642 if (eConnectionState_Associated !=
643 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState) {
Rajeev Kumar30cb6762016-07-28 20:01:15 -0700644 hdd_info("Offloads not supported in state %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800645 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->
646 conn_info.connState);
647 return;
648 }
649
650 hdd_conf_gtk_offload(pAdapter, fenable);
651
Houston Hoffman7260ecb2015-10-05 18:43:07 -0700652 /* Configure ARP/NS offload during cfg80211 suspend/resume and
653 * Enable MC address filtering during cfg80211 suspend
654 * only if active mode offload is disabled
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800655 */
656 if (!pHddCtx->config->active_mode_offload) {
Houston Hoffman7260ecb2015-10-05 18:43:07 -0700657 hdd_info("configuring unconfigured active mode offloads");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800658 hdd_conf_arp_offload(pAdapter, fenable);
Houston Hoffman7260ecb2015-10-05 18:43:07 -0700659 wlan_hdd_set_mc_addr_list(pAdapter, fenable);
660
Sravan Kumar Kairamfece87f2016-07-26 14:58:28 +0530661 if (pHddCtx->config->fhostNSOffload &&
662 pHddCtx->ns_offload_enable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800663 hdd_conf_ns_offload(pAdapter, fenable);
664 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530665 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800666 return;
667}
668#endif
669
670/**
671 * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function
672 * @work: registered work item
673 *
674 * This function performs the work initially trigged by a callback
675 * from the IPv4 netdev notifier. Since this means there has been a
676 * change in IPv4 state for the interface, the ARP offload is
677 * reconfigured.
678 *
679 * Return: None
680 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700681static void __hdd_ipv4_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800682{
683 hdd_adapter_t *pAdapter =
684 container_of(work, hdd_adapter_t, ipv4NotifierWorkQueue);
685 hdd_context_t *pHddCtx;
686 int status;
Deepak Dhamdheref16015f2016-06-01 14:28:09 -0700687 bool ndi_connected = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800688
689 hdd_info("Configuring ARP Offload");
690 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
691 status = wlan_hdd_validate_context(pHddCtx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530692 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800693 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800694
695 if (!pHddCtx->config->active_mode_offload) {
696 hdd_err("Active mode offload is disabled");
697 return;
698 }
699
700 if (false == pHddCtx->sus_res_mcastbcast_filter_valid) {
701 pHddCtx->sus_res_mcastbcast_filter =
702 pHddCtx->configuredMcastBcastFilter;
703 pHddCtx->sus_res_mcastbcast_filter_valid = true;
704 }
705
Deepak Dhamdheref16015f2016-06-01 14:28:09 -0700706 /* check if the device is in NAN data mode */
707 if (WLAN_HDD_IS_NDI(pAdapter))
708 ndi_connected = WLAN_HDD_IS_NDI_CONNECTED(pAdapter);
709
710 if (eConnectionState_Associated ==
711 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState ||
712 ndi_connected)
713 /*
714 * This invocation being part of the IPv4 registration callback,
715 * we are passing second parameter as 2 to avoid registration
716 * of IPv4 notifier again.
717 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800718 hdd_conf_arp_offload(pAdapter, true);
719}
720
721/**
722 * hdd_ipv4_notifier_work_queue() - IP V4 change notifier work handler
723 * @work: Pointer to work context
724 *
725 * Return: none
726 */
727void hdd_ipv4_notifier_work_queue(struct work_struct *work)
728{
729 cds_ssr_protect(__func__);
730 __hdd_ipv4_notifier_work_queue(work);
731 cds_ssr_unprotect(__func__);
732}
733
734/**
735 * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function
736 * @nb: notifier block that was registered with the kernel
737 * @data: (unused) generic data that was registered with the kernel
738 * @arg: (unused) generic argument that was registered with the kernel
739 *
740 * This is a callback function that is registered with the kernel via
741 * register_inetaddr_notifier() which allows the driver to be
742 * notified when there is an IPv4 address change.
743 *
744 * Return: NOTIFY_DONE to indicate we don't care what happens with
745 * other callbacks
746 */
747static int __wlan_hdd_ipv4_changed(struct notifier_block *nb,
748 unsigned long data, void *arg)
749{
750 struct in_ifaddr *ifa = (struct in_ifaddr *)arg;
751 struct in_ifaddr **ifap = NULL;
752 struct in_device *in_dev;
753
754 struct net_device *ndev = ifa->ifa_dev->dev;
755 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
756 hdd_context_t *pHddCtx;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700757 hdd_station_ctx_t *sta_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800758 int status;
759
Jeff Johnson158c8d02016-10-31 13:11:48 -0700760 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530761
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800762 if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700763 hdd_err("Adapter context is invalid %p", pAdapter);
Jeff Johnson158c8d02016-10-31 13:11:48 -0700764 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800765 }
766
Jeff Johnson158c8d02016-10-31 13:11:48 -0700767 if ((pAdapter->dev == ndev) &&
768 (pAdapter->device_mode == QDF_STA_MODE ||
769 pAdapter->device_mode == QDF_P2P_CLIENT_MODE ||
770 pAdapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800771
772 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
773 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530774 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800775 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800776
Jeff Johnson158c8d02016-10-31 13:11:48 -0700777 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Abhishek Singhca408032016-09-13 15:26:12 +0530778 if (eConnectionState_Associated ==
Jeff Johnson158c8d02016-10-31 13:11:48 -0700779 sta_ctx->conn_info.connState) {
780 hdd_info("invoking sme_dhcp_done_ind");
Abhishek Singhca408032016-09-13 15:26:12 +0530781 sme_dhcp_done_ind(pHddCtx->hHal,
Jeff Johnson158c8d02016-10-31 13:11:48 -0700782 pAdapter->sessionId);
783 }
Abhishek Singhca408032016-09-13 15:26:12 +0530784
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800785 if (!pHddCtx->config->fhostArpOffload) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700786 hdd_notice("Offload not enabled ARPOffload=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800787 pHddCtx->config->fhostArpOffload);
788 return NOTIFY_DONE;
789 }
790
791 in_dev = __in_dev_get_rtnl(pAdapter->dev);
792 if (in_dev) {
793 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
794 ifap = &ifa->ifa_next) {
795 if (!strcmp(pAdapter->dev->name,
796 ifa->ifa_label)) {
797 break; /* found */
798 }
799 }
800 }
801 if (ifa && ifa->ifa_local) {
802 schedule_work(&pAdapter->ipv4NotifierWorkQueue);
803 }
804 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530805 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800806 return NOTIFY_DONE;
807}
808
809/**
810 * wlan_hdd_ipv4_changed() - IPv4 change notifier callback
811 * @nb: pointer to notifier block
812 * @data: data
813 * @arg: arg
814 *
815 * This is the IPv4 notifier callback function gets invoked
816 * if any change in IP and then invoke the function @__wlan_hdd_ipv4_changed
817 * to reconfigure the offload parameters.
818 *
819 * Return: 0 on success, error number otherwise.
820 */
821int wlan_hdd_ipv4_changed(struct notifier_block *nb,
822 unsigned long data, void *arg)
823{
824 int ret;
825
826 cds_ssr_protect(__func__);
827 ret = __wlan_hdd_ipv4_changed(nb, data, arg);
828 cds_ssr_unprotect(__func__);
829
830 return ret;
831}
832
833/**
834 * hdd_conf_arp_offload() - Configure ARP offload
835 * @pAdapter: Adapter context for which ARP offload is to be configured
836 * @fenable: true : enable ARP offload false : disable arp offload
837 *
838 * Return:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530839 * QDF_STATUS_SUCCESS - on successful operation,
840 * QDF_STATUS_E_FAILURE - on failure of operation
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800841 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530842QDF_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, bool fenable)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800843{
844 struct in_ifaddr **ifap = NULL;
845 struct in_ifaddr *ifa = NULL;
846 struct in_device *in_dev;
847 int i = 0;
848 tSirHostOffloadReq offLoadRequest;
849 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
850
851 hdd_info("fenable = %d", fenable);
852
853 /* In SAP/P2P Go mode, ARP/NS Offload feature capability
854 * is controlled by one bit.
855 */
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800856 if ((QDF_SAP_MODE == pAdapter->device_mode ||
857 QDF_P2P_GO_MODE == pAdapter->device_mode) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800858 !pHddCtx->ap_arpns_support) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700859 hdd_notice("ARP Offload is not supported in SAP/P2PGO mode");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530860 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800861 }
862
863 if (fenable) {
864 in_dev = __in_dev_get_rtnl(pAdapter->dev);
865 if (in_dev) {
866 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
867 ifap = &ifa->ifa_next) {
868 if (!strcmp(pAdapter->dev->name,
869 ifa->ifa_label)) {
870 break; /* found */
871 }
872 }
873 }
874 if (ifa && ifa->ifa_local) {
875 offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD;
876 offLoadRequest.enableOrDisable = SIR_OFFLOAD_ENABLE;
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530877 hdd_wlan_offload_event(SIR_IPV4_ARP_REPLY_OFFLOAD,
878 SIR_OFFLOAD_ENABLE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800879
Jeff Johnsonc3273322016-07-06 15:28:17 -0700880 hdd_notice("Enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800881
882 if (((HDD_MCASTBCASTFILTER_FILTER_ALL_BROADCAST ==
883 pHddCtx->sus_res_mcastbcast_filter) ||
884 (HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST_BROADCAST
885 == pHddCtx->sus_res_mcastbcast_filter))
886 && (true ==
887 pHddCtx->sus_res_mcastbcast_filter_valid)) {
888 offLoadRequest.enableOrDisable =
889 SIR_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE;
Jeff Johnsonc3273322016-07-06 15:28:17 -0700890 hdd_notice("offload: inside arp offload conditional check");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800891 }
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530892 hdd_wlan_offload_event(
893 SIR_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE,
894 SIR_OFFLOAD_ENABLE);
Jeff Johnsonc3273322016-07-06 15:28:17 -0700895 hdd_notice("offload: arp filter programmed = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800896 offLoadRequest.enableOrDisable);
897
898 /* converting u32 to IPV4 address */
899 for (i = 0; i < 4; i++) {
900 offLoadRequest.params.hostIpv4Addr[i] =
901 (ifa->ifa_local >> (i * 8)) & 0xFF;
902 }
Jeff Johnsonc3273322016-07-06 15:28:17 -0700903 hdd_notice(" Enable SME HostOffload: %d.%d.%d.%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800904 offLoadRequest.params.hostIpv4Addr[0],
905 offLoadRequest.params.hostIpv4Addr[1],
906 offLoadRequest.params.hostIpv4Addr[2],
907 offLoadRequest.params.hostIpv4Addr[3]);
908
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530909 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800910 sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter),
911 pAdapter->sessionId,
912 &offLoadRequest)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700913 hdd_err("Failed to enable HostOffload feature");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530914 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800915 }
916 } else {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700917 hdd_notice("IP Address is not assigned");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800918 }
919
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530920 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800921 } else {
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530922 hdd_wlan_offload_event(SIR_IPV4_ARP_REPLY_OFFLOAD,
923 SIR_OFFLOAD_DISABLE);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530924 qdf_mem_zero((void *)&offLoadRequest,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800925 sizeof(tSirHostOffloadReq));
926 offLoadRequest.enableOrDisable = SIR_OFFLOAD_DISABLE;
927 offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD;
928
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530929 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800930 sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter),
931 pAdapter->sessionId, &offLoadRequest)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700932 hdd_err("Failure to disable host " "offload feature");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530933 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800934 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530935 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800936 }
937}
938
939/**
940 * hdd_mcbc_filter_modification() - MCBC Filter Modifier
941 * @pHddCtx: Global Hdd Context
942 * @pMcBcFilter: Multicast/Broadcast filter to be modified
943 *
944 * This function is called before setting mcbc filters
945 * to modify filter value considering different offloads
946 *
947 * Return: None.
948 */
949static void hdd_mcbc_filter_modification(hdd_context_t *pHddCtx,
950 uint8_t *pMcBcFilter)
951{
952 if (NULL == pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700953 hdd_err("NULL HDD context passed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800954 return;
955 }
956
957 *pMcBcFilter = pHddCtx->configuredMcastBcastFilter;
958 if (pHddCtx->config->fhostArpOffload) {
959 /* ARP offload is enabled, do not block bcast packets at RXP
960 * Will be using Bitmasking to reset the filter. As we have
961 * disable Broadcast filtering, Anding with the negation
962 * of Broadcast BIT
963 */
964 *pMcBcFilter &= ~(HDD_MCASTBCASTFILTER_FILTER_ALL_BROADCAST);
Agrawal Ashish02460a82015-09-16 17:20:30 +0530965 hdd_info("ARP offload is enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800966 }
967#ifdef WLAN_NS_OFFLOAD
968 if (pHddCtx->config->fhostNSOffload) {
969 /* NS offload is enabled, do not block mcast packets at RXP
970 * Will be using Bitmasking to reset the filter. As we have
971 * disable Multicast filtering, Anding with the negation
972 * of Multicast BIT
973 */
Agrawal Ashish02460a82015-09-16 17:20:30 +0530974 hdd_info("NS offload is enabled");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800975 *pMcBcFilter &= ~(HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST);
976 }
977#endif
978
979 pHddCtx->configuredMcastBcastFilter = *pMcBcFilter;
980}
981
982/**
983 * hdd_conf_mcastbcast_filter() - Configure multicast/broadcast filter
984 * @pHddCtx: Global HDD context
985 * @setfilter: true if filter is being set, false if filter is being cleared
986 *
987 * Return: None.
988 */
989void hdd_conf_mcastbcast_filter(hdd_context_t *pHddCtx, bool setfilter)
990{
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530991 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800992 tpSirWlanSetRxpFilters wlanRxpFilterParam =
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530993 qdf_mem_malloc(sizeof(tSirWlanSetRxpFilters));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994 if (NULL == wlanRxpFilterParam) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700995 hdd_alert("qdf_mem_malloc failed ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800996 return;
997 }
Jeff Johnsonc3273322016-07-06 15:28:17 -0700998 hdd_notice("Configuring Mcast/Bcast Filter Setting. setfilter %d", setfilter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800999 if (true == setfilter) {
1000 hdd_mcbc_filter_modification(pHddCtx,
1001 &wlanRxpFilterParam->
1002 configuredMcstBcstFilterSetting);
1003 } else {
1004 /*Use the current configured value to clear */
1005 wlanRxpFilterParam->configuredMcstBcstFilterSetting =
1006 pHddCtx->configuredMcastBcastFilter;
1007 }
1008
1009 wlanRxpFilterParam->setMcstBcstFilter = setfilter;
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301010 qdf_ret_status =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001011 sme_configure_rxp_filter(pHddCtx->hHal, wlanRxpFilterParam);
1012
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301013 if (setfilter && (QDF_STATUS_SUCCESS == qdf_ret_status))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001014 pHddCtx->hdd_mcastbcast_filter_set = true;
1015
Jeff Johnsonc3273322016-07-06 15:28:17 -07001016 hdd_notice("%s to post set/reset filter to lower mac with status %d configuredMcstBcstFilterSetting = %d setMcstBcstFilter = %d",
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301017 (QDF_STATUS_SUCCESS != qdf_ret_status) ? "Failed" : "Success",
1018 qdf_ret_status,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001019 wlanRxpFilterParam->configuredMcstBcstFilterSetting,
1020 wlanRxpFilterParam->setMcstBcstFilter);
1021
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301022 if (QDF_STATUS_SUCCESS != qdf_ret_status)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301023 qdf_mem_free(wlanRxpFilterParam);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001024}
1025
1026#ifdef WLAN_FEATURE_PACKET_FILTERING
1027/**
1028 * wlan_hdd_set_mc_addr_list() - set MC address list in FW
1029 * @pAdapter: adapter whose MC list is being set
1030 * @set: flag which indicates if addresses are being set or cleared
1031 */
1032void wlan_hdd_set_mc_addr_list(hdd_adapter_t *pAdapter, uint8_t set)
1033{
1034 uint8_t i;
1035 tpSirRcvFltMcAddrList pMulticastAddrs = NULL;
1036 tHalHandle hHal = NULL;
1037 hdd_context_t *pHddCtx = (hdd_context_t *) pAdapter->pHddCtx;
Ravi Joshi24477b72016-07-19 15:45:09 -07001038 hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039
Ravi Joshi24477b72016-07-19 15:45:09 -07001040 ENTER();
1041
1042 if (wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001043 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001044
1045 hHal = pHddCtx->hHal;
1046
1047 if (NULL == hHal) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001048 hdd_err("HAL Handle is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001049 return;
1050 }
1051
Ravi Joshi24477b72016-07-19 15:45:09 -07001052 if (!sta_ctx) {
1053 hdd_err("sta_ctx is NULL");
1054 return;
1055 }
1056
1057 /* Check if INI is enabled or not, other wise just return */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001058 if (!pHddCtx->config->fEnableMCAddrList) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001059 hdd_notice("gMCAddrListEnable is not enabled in INI");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001060 return;
1061 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301062 pMulticastAddrs = qdf_mem_malloc(sizeof(tSirRcvFltMcAddrList));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001063 if (NULL == pMulticastAddrs) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001064 hdd_err("Could not allocate Memory");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065 return;
1066 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001067 pMulticastAddrs->action = set;
1068
1069 if (set) {
Ravi Joshi24477b72016-07-19 15:45:09 -07001070 /*
1071 * Following pre-conditions should be satisfied before we
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001072 * configure the MC address list.
1073 */
Ravi Joshi24477b72016-07-19 15:45:09 -07001074 if (pAdapter->mc_addr_list.mc_cnt &&
1075 (((pAdapter->device_mode == QDF_STA_MODE ||
1076 pAdapter->device_mode == QDF_P2P_CLIENT_MODE) &&
1077 hdd_conn_is_connected(sta_ctx)) ||
1078 (WLAN_HDD_IS_NDI(pAdapter) &&
1079 WLAN_HDD_IS_NDI_CONNECTED(pAdapter)))) {
1080
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001081 pMulticastAddrs->ulMulticastAddrCnt =
1082 pAdapter->mc_addr_list.mc_cnt;
Ravi Joshi24477b72016-07-19 15:45:09 -07001083
1084 for (i = 0; i < pAdapter->mc_addr_list.mc_cnt; i++) {
Srinivas Girigowda98530492015-11-20 17:39:24 -08001085 memcpy(pMulticastAddrs->multicastAddr[i].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001086 pAdapter->mc_addr_list.addr[i],
Ravi Joshi24477b72016-07-19 15:45:09 -07001087 sizeof(pAdapter->mc_addr_list.addr[i]));
Srinivas Girigowda98530492015-11-20 17:39:24 -08001088 hdd_info("%s multicast filter: addr ="
1089 MAC_ADDRESS_STR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001090 set ? "setting" : "clearing",
1091 MAC_ADDR_ARRAY(pMulticastAddrs->
Srinivas Girigowda98530492015-11-20 17:39:24 -08001092 multicastAddr[i].bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001093 }
1094 /* Set multicast filter */
1095 sme_8023_multicast_list(hHal, pAdapter->sessionId,
1096 pMulticastAddrs);
Sachin Ahujaa69c72a2016-09-03 15:59:33 +05301097 } else {
1098 hdd_info("MC address list not sent to FW, cnt: %d",
1099 pAdapter->mc_addr_list.mc_cnt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001100 }
1101 } else {
1102 /* Need to clear only if it was previously configured */
1103 if (pAdapter->mc_addr_list.isFilterApplied) {
1104 pMulticastAddrs->ulMulticastAddrCnt =
1105 pAdapter->mc_addr_list.mc_cnt;
Ravi Joshi24477b72016-07-19 15:45:09 -07001106 for (i = 0; i < pAdapter->mc_addr_list.mc_cnt; i++) {
Srinivas Girigowda98530492015-11-20 17:39:24 -08001107 memcpy(pMulticastAddrs->multicastAddr[i].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108 pAdapter->mc_addr_list.addr[i],
Ravi Joshi24477b72016-07-19 15:45:09 -07001109 sizeof(pAdapter->mc_addr_list.addr[i]));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001110 }
1111 sme_8023_multicast_list(hHal, pAdapter->sessionId,
1112 pMulticastAddrs);
1113 }
1114
1115 }
1116 /* MAddrCnt is MulticastAddrCnt */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001117 hdd_notice("smeSessionId:%d; set:%d; MCAdddrCnt :%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118 pAdapter->sessionId, set,
1119 pMulticastAddrs->ulMulticastAddrCnt);
1120
1121 pAdapter->mc_addr_list.isFilterApplied = set ? true : false;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301122 qdf_mem_free(pMulticastAddrs);
Ravi Joshi24477b72016-07-19 15:45:09 -07001123
1124 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001125 return;
1126}
1127#endif
1128
1129/**
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001130 * hdd_update_mcastbcast_filter(): cache multi and broadcast filter for suspend
1131 * @hdd_ctx: hdd context
1132 *
1133 * Cache the configured filter to be used in suspend resume.
1134 */
1135static void hdd_update_mcastbcast_filter(hdd_context_t *hdd_ctx)
1136{
1137 if (false == hdd_ctx->sus_res_mcastbcast_filter_valid) {
1138 hdd_ctx->sus_res_mcastbcast_filter =
1139 hdd_ctx->configuredMcastBcastFilter;
1140 hdd_ctx->sus_res_mcastbcast_filter_valid = true;
1141 hdd_info("configuredMCastBcastFilter saved = %d",
1142 hdd_ctx->configuredMcastBcastFilter);
1143 }
1144}
1145
1146/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001147 * hdd_conf_suspend_ind() - Send Suspend notification
1148 * @pHddCtx: HDD Global context
1149 * @pAdapter: adapter being suspended
1150 * @callback: callback function to be called upon completion
1151 * @callbackContext: callback context to be passed back to callback function
1152 *
1153 * Return: None.
1154 */
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001155static void hdd_send_suspend_ind(hdd_context_t *pHddCtx,
1156 uint32_t conn_state_mask,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001157 void (*callback)(void *callbackContext,
1158 bool suspended),
1159 void *callbackContext)
1160{
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301161 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001162
Jeff Johnsonc3273322016-07-06 15:28:17 -07001163 hdd_info("send wlan suspend indication");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001164
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301165 qdf_ret_status =
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001166 sme_configure_suspend_ind(pHddCtx->hHal, conn_state_mask,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001167 callback, callbackContext);
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001168
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301169 if (QDF_STATUS_SUCCESS == qdf_ret_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001170 pHddCtx->hdd_mcastbcast_filter_set = true;
1171 } else {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001172 hdd_err("sme_configure_suspend_ind returned failure %d",
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301173 qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001174 }
1175}
1176
1177/**
1178 * hdd_conf_suspend_ind() - Send Resume notification
1179 * @pAdapter: adapter being resumed
1180 *
1181 * Return: None.
1182 */
1183static void hdd_conf_resume_ind(hdd_adapter_t *pAdapter)
1184{
1185 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301186 QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001187
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301188 qdf_ret_status = sme_configure_resume_req(pHddCtx->hHal, NULL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001189
Anurag Chouhanf04e84f2016-03-03 10:12:12 +05301190 if (QDF_STATUS_SUCCESS != qdf_ret_status) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001191 hdd_err("sme_configure_resume_req return failure %d", qdf_ret_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001192
1193 }
1194
Jeff Johnsonc3273322016-07-06 15:28:17 -07001195 hdd_notice("send wlan resume indication");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001196 /* Disable supported OffLoads */
1197 hdd_conf_hostoffload(pAdapter, false);
1198 pHddCtx->hdd_mcastbcast_filter_set = false;
1199
1200 if (true == pHddCtx->sus_res_mcastbcast_filter_valid) {
1201 pHddCtx->configuredMcastBcastFilter =
1202 pHddCtx->sus_res_mcastbcast_filter;
1203 pHddCtx->sus_res_mcastbcast_filter_valid = false;
1204 }
1205
Jeff Johnsonc3273322016-07-06 15:28:17 -07001206 hdd_notice("offload: in hdd_conf_resume_ind, restoring configuredMcastBcastFilter");
1207 hdd_notice("configuredMcastBcastFilter = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001208 pHddCtx->configuredMcastBcastFilter);
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001209}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001210
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001211/**
1212 * hdd_update_conn_state_mask(): record info needed by wma_suspend_req
1213 * @adapter: adapter to get info from
1214 * @conn_state_mask: mask of connection info
1215 *
1216 * currently only need to send connection info.
1217 */
1218static void
1219hdd_update_conn_state_mask(hdd_adapter_t *adapter, uint32_t *conn_state_mask)
1220{
1221
1222 eConnectionState connState;
1223 hdd_station_ctx_t *sta_ctx;
1224 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1225 connState = sta_ctx->conn_info.connState;
1226
1227 if (connState == eConnectionState_Associated ||
1228 connState == eConnectionState_IbssConnected)
1229 *conn_state_mask |= (1 << adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001230}
1231
1232/**
1233 * hdd_suspend_wlan() - Driver suspend function
1234 * @callback: Callback function to invoke when driver is ready to suspend
1235 * @callbackContext: Context to pass back to @callback function
1236 *
1237 * Return: None.
1238 */
1239static void
1240hdd_suspend_wlan(void (*callback)(void *callbackContext, bool suspended),
1241 void *callbackContext)
1242{
1243 hdd_context_t *pHddCtx;
1244
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301245 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001246 hdd_adapter_t *pAdapter = NULL;
1247 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001248 uint32_t conn_state_mask = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001249
Jeff Johnsonc3273322016-07-06 15:28:17 -07001250 hdd_info("WLAN being suspended by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001251
Anurag Chouhan6d760662016-02-20 16:05:43 +05301252 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001253 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001254 hdd_alert("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001255 return;
1256 }
1257
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001258 if (cds_is_driver_recovering()) {
1259 hdd_err("Recovery in Progress. State: 0x%x Ignore suspend!!!",
1260 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001261 return;
1262 }
1263
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001264 hdd_update_mcastbcast_filter(pHddCtx);
1265
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001266 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301267 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001268 pAdapter = pAdapterNode->pAdapter;
1269
1270 /* stop all TX queues before suspend */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001271 hdd_notice("Disabling queues");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001272 wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE,
1273 WLAN_CONTROL_PATH);
1274
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001275 /* Configure supported OffLoads */
1276 hdd_conf_hostoffload(pAdapter, true);
1277
1278 hdd_update_conn_state_mask(pAdapter, &conn_state_mask);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001279
1280 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001281
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001282 pAdapterNode = pNext;
1283 }
1284
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001285 hdd_send_suspend_ind(pHddCtx, conn_state_mask, callback,
1286 callbackContext);
1287
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001288 pHddCtx->hdd_wlan_suspended = true;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301289 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001290
1291 return;
1292}
1293
1294/**
1295 * hdd_resume_wlan() - Driver resume function
1296 *
1297 * Return: None.
1298 */
1299static void hdd_resume_wlan(void)
1300{
1301 hdd_context_t *pHddCtx;
1302 hdd_adapter_t *pAdapter = NULL;
1303 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301304 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001305
Dustin Brown2d228232016-09-22 15:06:19 -07001306 hdd_info("WLAN being resumed by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001307
Anurag Chouhan6d760662016-02-20 16:05:43 +05301308 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001309 if (!pHddCtx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001310 hdd_err("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001311 return;
1312 }
1313
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001314 if (cds_is_driver_recovering()) {
Dustin Brown2d228232016-09-22 15:06:19 -07001315 hdd_err("Recovery in Progress. State: 0x%x Ignore resume!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001316 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001317 return;
1318 }
1319
1320 pHddCtx->hdd_wlan_suspended = false;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301321 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001322
1323 /*loop through all adapters. Concurrency */
1324 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
1325
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301326 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001327 pAdapter = pAdapterNode->pAdapter;
1328
1329 /* wake the tx queues */
Dustin Brown2d228232016-09-22 15:06:19 -07001330 hdd_info("Enabling queues");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001331 wlan_hdd_netif_queue_control(pAdapter,
1332 WLAN_WAKE_ALL_NETIF_QUEUE,
1333 WLAN_CONTROL_PATH);
1334
1335 hdd_conf_resume_ind(pAdapter);
1336
1337 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1338 pAdapterNode = pNext;
1339 }
1340 hdd_ipa_resume(pHddCtx);
1341
1342 return;
1343}
1344
1345/**
1346 * DOC: SSR Timer
1347 *
1348 * When SSR is initiated, an SSR timer is started. Under normal
1349 * circumstances SSR should complete amd the timer should be deleted
1350 * before it fires. If the SSR timer does fire, it indicates SSR has
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301351 * taken too long, and our only recourse is to invoke the QDF_BUG()
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001352 * API which can allow a crashdump to be captured.
1353 */
1354
1355/**
1356 * hdd_ssr_timer_init() - Initialize SSR Timer
1357 *
1358 * Return: None.
1359 */
1360static void hdd_ssr_timer_init(void)
1361{
1362 init_timer(&ssr_timer);
1363}
1364
1365/**
1366 * hdd_ssr_timer_del() - Delete SSR Timer
1367 *
1368 * Return: None.
1369 */
1370static void hdd_ssr_timer_del(void)
1371{
1372 del_timer(&ssr_timer);
1373 ssr_timer_started = false;
1374}
1375
1376/**
1377 * hdd_ssr_timer_cb() - SSR Timer callback function
1378 * @data: opaque data registered with timer infrastructure
1379 *
1380 * Return: None.
1381 */
1382static void hdd_ssr_timer_cb(unsigned long data)
1383{
Jeff Johnsonc3273322016-07-06 15:28:17 -07001384 hdd_alert("HDD SSR timer expired!");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301385 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001386}
1387
1388/**
1389 * hdd_ssr_timer_start() - Start SSR Timer
1390 * @msec: Timer timeout value in milliseconds
1391 *
1392 * Return: None.
1393 */
1394static void hdd_ssr_timer_start(int msec)
1395{
1396 if (ssr_timer_started) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001397 hdd_alert("Trying to start SSR timer when " "it's running!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001398 }
1399 ssr_timer.expires = jiffies + msecs_to_jiffies(msec);
1400 ssr_timer.function = hdd_ssr_timer_cb;
1401 add_timer(&ssr_timer);
1402 ssr_timer_started = true;
1403}
1404
1405/**
Komal Seelam78ff65a2016-08-18 15:25:24 +05301406 * hdd_svc_fw_shutdown_ind() - API to send FW SHUTDOWN IND to Userspace
1407 *
1408 * @dev: Device Pointer
1409 *
1410 * Return: None
1411 */
1412void hdd_svc_fw_shutdown_ind(struct device *dev)
1413{
1414 hdd_context_t *hdd_ctx;
1415 v_CONTEXT_t g_context;
1416
1417 g_context = cds_get_global_context();
1418
1419 if (!g_context)
1420 return;
1421
1422 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1423
1424 hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
1425 WLAN_SVC_FW_SHUTDOWN_IND,
1426 NULL, 0) : 0;
1427}
1428
1429/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001430 * hdd_wlan_shutdown() - HDD SSR shutdown function
1431 *
1432 * This function is called by the HIF to shutdown the driver during SSR.
1433 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301434 * Return: QDF_STATUS_SUCCESS if the driver was shut down,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001435 * or an error status otherwise
1436 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301437QDF_STATUS hdd_wlan_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001439 v_CONTEXT_t p_cds_context = NULL;
1440 hdd_context_t *pHddCtx;
1441 p_cds_sched_context cds_sched_context = NULL;
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001442 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001443
Jeff Johnsonc3273322016-07-06 15:28:17 -07001444 hdd_alert("WLAN driver shutting down!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001445
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001446 /* If SSR never completes, then do kernel panic. */
1447 hdd_ssr_timer_init();
1448 hdd_ssr_timer_start(HDD_SSR_BRING_UP_TIME);
1449
1450 /* Get the global CDS context. */
1451 p_cds_context = cds_get_global_context();
1452 if (!p_cds_context) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001453 hdd_alert("Global CDS context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301454 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001455 }
1456
1457 /* Get the HDD context. */
Anurag Chouhan6d760662016-02-20 16:05:43 +05301458 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001459 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001460 hdd_alert("HDD context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301461 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001462 }
1463
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 cds_clear_concurrent_session_count();
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301465
1466 hdd_info("Invoking packetdump deregistration API");
1467 wlan_deregister_txrx_packetdump();
1468
Sandeep Puligillae390be52016-02-08 17:07:05 -08001469 hdd_cleanup_scan_queue(pHddCtx);
Govind Singh9c58eba2016-09-02 16:23:06 +05301470 hdd_ipa_uc_ssr_deinit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001471 hdd_reset_all_adapters(pHddCtx);
1472
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301473 /* Flush cached rx frame queue */
1474 cds_flush_cache_rx_queue();
1475
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301476 /* De-register the HDD callbacks */
1477 hdd_deregister_cb(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001478
1479 cds_sched_context = get_cds_sched_ctxt();
1480
1481 /* Wakeup all driver threads */
1482 if (true == pHddCtx->isMcThreadSuspended) {
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001483 scheduler_resume_complete();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001484 pHddCtx->isMcThreadSuspended = false;
1485 }
1486#ifdef QCA_CONFIG_SMP
1487 if (true == pHddCtx->is_ol_rx_thread_suspended) {
1488 complete(&cds_sched_context->ol_resume_rx_event);
1489 pHddCtx->is_ol_rx_thread_suspended = false;
1490 }
1491#endif
1492
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001493 qdf_status = cds_sched_close(p_cds_context);
1494 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1495 hdd_err("Failed to close CDS Scheduler");
1496 QDF_ASSERT(false);
1497 }
1498
Prashanth Bhattaab004382016-10-11 16:08:11 -07001499 hdd_bus_bandwidth_destroy(pHddCtx);
1500
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301501 wlansap_global_deinit();
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001502 hdd_wlan_stop_modules(pHddCtx);
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301503
Jeff Johnsonf7f66f02016-09-23 14:50:11 -07001504 hdd_lpass_notify_stop(pHddCtx);
Yuanyuan Liu3e918e52016-08-17 15:41:35 -07001505
Jeff Johnsonc3273322016-07-06 15:28:17 -07001506 hdd_alert("WLAN driver shutdown complete");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301507 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001508}
1509
1510/**
1511 * hdd_wlan_re_init() - HDD SSR re-init function
1512 *
1513 * This function is called by the HIF to re-initialize the driver after SSR.
1514 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301515 * Return: QDF_STATUS_SUCCESS if the driver was re-initialized,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001516 * or an error status otherwise
1517 */
Arun Khandavallifae92942016-08-01 13:31:08 +05301518QDF_STATUS hdd_wlan_re_init(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001519{
Arun Khandavallifae92942016-08-01 13:31:08 +05301520
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001521 v_CONTEXT_t p_cds_context = NULL;
1522 hdd_context_t *pHddCtx = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001523 hdd_adapter_t *pAdapter;
Arun Khandavallifae92942016-08-01 13:31:08 +05301524 QDF_STATUS qdf_status;
1525 int ret;
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301526 bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001527
1528 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1529
1530 /* Get the CDS context */
1531 p_cds_context = cds_get_global_context();
1532 if (p_cds_context == NULL) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001533 hdd_alert("Failed cds_get_global_context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001534 goto err_re_init;
1535 }
1536
1537 /* Get the HDD context */
Anurag Chouhan6d760662016-02-20 16:05:43 +05301538 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001539 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001540 hdd_alert("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001541 goto err_re_init;
1542 }
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301543 bug_on_reinit_failure = pHddCtx->config->bug_on_reinit_failure;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001544
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001545 /* The driver should always be initialized in STA mode after SSR */
1546 hdd_set_conparam(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001547 /* Try to get an adapter from mode ID */
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001548 pAdapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001549 if (!pAdapter) {
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001550 pAdapter = hdd_get_adapter(pHddCtx, QDF_SAP_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001551 if (!pAdapter) {
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001552 pAdapter = hdd_get_adapter(pHddCtx, QDF_IBSS_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001553 if (!pAdapter) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001554 hdd_alert("Failed to get Adapter!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001555 }
1556 }
1557 }
1558
Nirav Shahcc1f1ae2016-04-26 11:41:29 +05301559 if (pHddCtx->config->enable_dp_trace)
1560 qdf_dp_trace_init();
1561
Prashanth Bhattaab004382016-10-11 16:08:11 -07001562 hdd_bus_bandwidth_init(pHddCtx);
1563
Arun Khandavallifae92942016-08-01 13:31:08 +05301564 ret = hdd_wlan_start_modules(pHddCtx, pAdapter, true);
1565 if (ret) {
1566 hdd_err("Failed to start wlan after error");
1567 goto err_wiphy_unregister;
1568 }
1569
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001570 if (hdd_ipa_uc_ssr_reinit())
Jeff Johnsonc3273322016-07-06 15:28:17 -07001571 hdd_err("HDD IPA UC reinit failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001572
Arun Khandavallia96c2c02016-05-17 19:15:34 +05301573 hdd_wlan_get_version(pHddCtx, NULL, NULL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001575 /* Restart all adapters */
1576 hdd_start_all_adapters(pHddCtx);
1577
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001578 pHddCtx->hdd_mcastbcast_filter_set = false;
1579 pHddCtx->btCoexModeSet = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580
Kondabattini, Ganesh96ac37b2016-09-02 23:12:15 +05301581 wlan_hdd_send_svc_nlink_msg(pHddCtx->radio_index,
1582 WLAN_SVC_FW_CRASHED_IND, NULL, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001583
1584 /* Allow the phone to go to sleep */
1585 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1586
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301587 ret = hdd_register_cb(pHddCtx);
1588 if (ret) {
1589 hdd_err("Failed to register HDD callbacks!");
Chandrasekaran Manishekarcde33d72016-04-14 19:03:39 +05301590 goto err_cds_disable;
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301591 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001592
Jeff Johnson9afc5012016-09-23 13:56:27 -07001593 hdd_lpass_notify_start(pHddCtx);
Manishekar Chandrasekaran2e71e932016-06-24 02:31:55 +05301594 qdf_status = wlansap_global_init();
1595 if (QDF_IS_STATUS_ERROR(qdf_status))
1596 goto err_cds_disable;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001597
Srinivas Girigowdad9e6f7b2016-02-01 19:37:52 -08001598 if (cds_is_packet_log_enabled())
Poddar, Siddarth176c4362016-10-03 12:25:00 +05301599 hdd_pktlog_enable_disable(pHddCtx, true, 0, 0);
Srinivas Girigowdad9e6f7b2016-02-01 19:37:52 -08001600
Jeff Johnsonc3273322016-07-06 15:28:17 -07001601 hdd_err("WLAN host driver reinitiation completed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001602 goto success;
1603
1604err_cds_disable:
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001605 hdd_wlan_stop_modules(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001606
Arun Khandavallifae92942016-08-01 13:31:08 +05301607err_wiphy_unregister:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001608 if (pHddCtx) {
1609 /* Unregister the Net Device Notifier */
1610 unregister_netdevice_notifier(&hdd_netdev_notifier);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001611 ptt_sock_deactivate_svc();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001612 nl_srv_exit();
1613
1614 /* Free up dynamically allocated members inside HDD Adapter */
1615 kfree(pHddCtx->config);
1616 pHddCtx->config = NULL;
Nirav Shahed34b212016-04-25 10:59:16 +05301617 wlan_hdd_deinit_tx_rx_histogram(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001618 wiphy_unregister(pHddCtx->wiphy);
1619 wiphy_free(pHddCtx->wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001620 }
1621
1622err_re_init:
1623 /* Allow the phone to go to sleep */
1624 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301625 if (bug_on_reinit_failure)
1626 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001627 return -EPERM;
1628
1629success:
Srinivas Girigowda02c084d2016-10-18 15:27:21 -07001630 hdd_ssr_timer_del();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301631 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001632}
1633
1634/**
1635 * wlan_hdd_set_powersave() - Set powersave mode
1636 * @adapter: adapter upon which the request was received
Dustin Brownf660fb42016-09-09 12:04:00 -07001637 * @allow_power_save: is wlan allowed to go into power save mode
1638 * @timeout: timeout period in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001639 *
1640 * Return: 0 on success, non-zero on any error
1641 */
Dustin Brownf660fb42016-09-09 12:04:00 -07001642static int wlan_hdd_set_powersave(hdd_adapter_t *adapter,
1643 bool allow_power_save, uint32_t timeout)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001644{
1645 tHalHandle hal;
1646 hdd_context_t *hdd_ctx;
1647
1648 if (NULL == adapter) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001649 hdd_alert("Adapter NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001650 return -ENODEV;
1651 }
1652
1653 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1654 if (!hdd_ctx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001655 hdd_err("hdd context is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001656 return -EINVAL;
1657 }
1658
Dustin Brownf660fb42016-09-09 12:04:00 -07001659 hdd_info("Allow power save: %d", allow_power_save);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001660 hal = WLAN_HDD_GET_HAL_CTX(adapter);
1661
Dustin Brownf660fb42016-09-09 12:04:00 -07001662 if (allow_power_save) {
1663 if (QDF_STA_MODE == adapter->device_mode ||
1664 QDF_P2P_CLIENT_MODE == adapter->device_mode) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001665 hdd_notice("Disabling Auto Power save timer");
Dustin Brownf660fb42016-09-09 12:04:00 -07001666 sme_ps_disable_auto_ps_timer(
1667 WLAN_HDD_GET_HAL_CTX(adapter),
1668 adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001669 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001670
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001671 if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001672 hdd_notice("Wlan driver Entering Power save");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001673
1674 /*
1675 * Enter Power Save command received from GUI
1676 * this means DHCP is completed
1677 */
1678 sme_ps_enable_disable(hal, adapter->sessionId,
1679 SME_PS_ENABLE);
1680 } else {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001681 hdd_info("Power Save is not enabled in the cfg");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001682 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001683 } else {
1684 hdd_info("Wlan driver Entering Full Power");
1685
1686 /*
1687 * Enter Full power command received from GUI
1688 * this means we are disconnected
1689 */
1690 sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1691 adapter->sessionId);
1692 sme_ps_enable_disable(hal, adapter->sessionId, SME_PS_DISABLE);
1693 sme_ps_enable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1694 adapter->sessionId, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001696
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697 return 0;
1698}
1699
Dustin Brown105d7902016-10-03 16:27:59 -07001700static void wlan_hdd_print_suspend_fail_stats(hdd_context_t *hdd_ctx)
1701{
1702 hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d",
1703 hdd_ctx->suspend_fail_stats[SUSPEND_FAIL_IPA],
1704 hdd_ctx->suspend_fail_stats[SUSPEND_FAIL_RADAR],
1705 hdd_ctx->suspend_fail_stats[SUSPEND_FAIL_ROAM],
1706 hdd_ctx->suspend_fail_stats[SUSPEND_FAIL_SCAN],
1707 hdd_ctx->suspend_fail_stats[SUSPEND_FAIL_INITIAL_WAKEUP]);
1708}
1709
1710void wlan_hdd_inc_suspend_stats(hdd_context_t *hdd_ctx,
1711 enum suspend_fail_reason reason)
1712{
1713 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
1714 hdd_ctx->suspend_fail_stats[reason]++;
1715 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
1716}
1717
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718/**
1719 * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1720 * @wiphy: Pointer to wiphy
1721 *
1722 * This API is called when cfg80211 driver resumes driver updates
1723 * latest sched_scan scan result(if any) to cfg80211 database
1724 *
1725 * Return: integer status
1726 */
1727static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1728{
1729 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1730 hdd_adapter_t *pAdapter;
1731 hdd_adapter_list_node_t *pAdapterNode, *pNext;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301732 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001733 int result;
1734 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1735
1736 ENTER();
1737
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001738 if (cds_is_driver_recovering())
1739 return 0;
1740
Anurag Chouhan6d760662016-02-20 16:05:43 +05301741 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001742 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001743 return -EINVAL;
1744 }
1745
1746 result = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301747 if (0 != result)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001748 return result;
Arun Khandavallifae92942016-08-01 13:31:08 +05301749
1750 mutex_lock(&pHddCtx->iface_change_lock);
1751 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
1752 mutex_unlock(&pHddCtx->iface_change_lock);
1753 hdd_info("Driver Module not enabled return success");
1754 return 0;
1755 }
1756 mutex_unlock(&pHddCtx->iface_change_lock);
Yuanyuan Liu13738502016-04-06 17:41:37 -07001757 pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_MEDIUM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758
1759 /* Resume MC thread */
1760 if (pHddCtx->isMcThreadSuspended) {
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001761 scheduler_resume_complete();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001762 pHddCtx->isMcThreadSuspended = false;
1763 }
1764#ifdef QCA_CONFIG_SMP
1765 /* Resume tlshim Rx thread */
1766 if (pHddCtx->is_ol_rx_thread_suspended) {
1767 complete(&cds_sched_context->ol_resume_rx_event);
1768 pHddCtx->is_ol_rx_thread_suspended = false;
1769 }
1770#endif
1771 hdd_resume_wlan();
1772
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301773 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301774 TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
1775 NO_SESSION, pHddCtx->isWiphySuspended));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301776 qdf_spin_lock(&pHddCtx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001777 pHddCtx->isWiphySuspended = false;
1778 if (true != pHddCtx->isSchedScanUpdatePending) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301779 qdf_spin_unlock(&pHddCtx->sched_scan_lock);
Dustin Brown2d228232016-09-22 15:06:19 -07001780 hdd_info("Return resume is not due to PNO indication");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001781 return 0;
1782 }
1783 /* Reset flag to avoid updatating cfg80211 data old results again */
1784 pHddCtx->isSchedScanUpdatePending = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301785 qdf_spin_unlock(&pHddCtx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786
1787 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
1788
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301789 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001790 pAdapter = pAdapterNode->pAdapter;
1791 if ((NULL != pAdapter) &&
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001792 (QDF_STA_MODE == pAdapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001793 if (0 !=
1794 wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy,
1795 pAdapter, 0)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001796 hdd_warn("NO SCAN result");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001797 } else {
1798 /* Acquire wakelock to handle the case where
1799 * APP's tries to suspend immediately after
1800 * updating the scan results. Whis results in
1801 * app's is in suspended state and not able to
1802 * process the connect request to AP
1803 */
Sreelakshmi Konamki22528532016-09-06 16:34:50 +05301804 hdd_prevent_suspend_timeout(
1805 HDD_WAKE_LOCK_RESUME_DURATION,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001806 WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN);
1807 cfg80211_sched_scan_results(pHddCtx->wiphy);
1808 }
1809
Dustin Brown2d228232016-09-22 15:06:19 -07001810 hdd_info("cfg80211 scan result database updated");
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301811 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001812 return result;
1813 }
1814 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1815 pAdapterNode = pNext;
1816 }
1817
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301818 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001819 return result;
1820}
1821
1822/**
1823 * wlan_hdd_cfg80211_ready_to_suspend() - set cfg80211 ready to suspend event
1824 * @callbackContext: Pointer to callback context
1825 * @suspended: Suspend flag
1826 *
1827 * Return: none
1828 */
1829static void wlan_hdd_cfg80211_ready_to_suspend(void *callbackContext,
1830 bool suspended)
1831{
1832 hdd_context_t *pHddCtx = (hdd_context_t *) callbackContext;
1833 pHddCtx->suspended = suspended;
1834 complete(&pHddCtx->ready_to_suspend);
1835}
1836
1837/**
1838 * wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1839 * @wiphy: Pointer to wiphy
1840 *
1841 * This API is called when cfg80211 driver resumes driver updates
1842 * latest sched_scan scan result(if any) to cfg80211 database
1843 *
1844 * Return: integer status
1845 */
1846int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1847{
1848 int ret;
1849
1850 cds_ssr_protect(__func__);
1851 ret = __wlan_hdd_cfg80211_resume_wlan(wiphy);
1852 cds_ssr_unprotect(__func__);
1853
1854 return ret;
1855}
1856
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001857static void hdd_suspend_cb(void)
1858{
1859 hdd_context_t *hdd_ctx;
1860
1861 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1862 if (!hdd_ctx) {
1863 cds_err("HDD context is NULL");
1864 return;
1865 }
1866
1867 complete(&hdd_ctx->mc_sus_event_var);
1868}
1869
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001870/**
1871 * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1872 * @wiphy: Pointer to wiphy
1873 * @wow: Pointer to wow
1874 *
1875 * This API is called when cfg80211 driver suspends
1876 *
1877 * Return: integer status
1878 */
1879static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1880 struct cfg80211_wowlan *wow)
1881{
1882#ifdef QCA_CONFIG_SMP
1883#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */
1884#endif
1885 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1886 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1887 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
1888 hdd_adapter_t *pAdapter;
1889 hdd_scaninfo_t *pScanInfo;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301890 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891 int rc;
1892
1893 ENTER();
1894
Anurag Chouhan6d760662016-02-20 16:05:43 +05301895 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001896 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001897 return -EINVAL;
1898 }
1899
1900 rc = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301901 if (0 != rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001902 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001903
Arun Khandavallifae92942016-08-01 13:31:08 +05301904 mutex_lock(&pHddCtx->iface_change_lock);
1905 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
1906 mutex_unlock(&pHddCtx->iface_change_lock);
1907 hdd_info("Driver Modules not Enabled ");
1908 return 0;
1909 }
1910 mutex_unlock(&pHddCtx->iface_change_lock);
1911
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001912 /* If RADAR detection is in progress (HDD), prevent suspend. The flag
1913 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true
1914 * until CAC is done for a SoftAP which is in started state.
1915 */
1916 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301917 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001918 pAdapter = pAdapterNode->pAdapter;
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301919
1920 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1921 hdd_err("invalid session id: %d", pAdapter->sessionId);
1922 goto next_adapter;
1923 }
1924
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001925 if (QDF_SAP_MODE == pAdapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001926 if (BSS_START ==
1927 WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter)->bssState &&
1928 true ==
1929 WLAN_HDD_GET_AP_CTX_PTR(pAdapter)->
1930 dfs_cac_block_tx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001931 hdd_err("RADAR detection in progress, do not allow suspend");
Dustin Brown105d7902016-10-03 16:27:59 -07001932 wlan_hdd_inc_suspend_stats(pHddCtx,
1933 SUSPEND_FAIL_RADAR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001934 return -EAGAIN;
1935 } else if (!pHddCtx->config->enableSapSuspend) {
1936 /* return -EOPNOTSUPP if SAP does not support
1937 * suspend
1938 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001939 hdd_err("SAP does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001940 return -EOPNOTSUPP;
1941 }
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001942 } else if (QDF_P2P_GO_MODE == pAdapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001943 if (!pHddCtx->config->enableSapSuspend) {
1944 /* return -EOPNOTSUPP if GO does not support
1945 * suspend
1946 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001947 hdd_err("GO does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001948 return -EOPNOTSUPP;
1949 }
1950 }
Masti, Narayanraddi3e26de62016-08-19 14:33:22 +05301951 if (pAdapter->is_roc_inprogress)
1952 wlan_hdd_cleanup_remain_on_channel_ctx(pAdapter);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301953next_adapter:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1955 pAdapterNode = pNext;
1956 }
1957
1958 /* Stop ongoing scan on each interface */
1959 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301960 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001961 pAdapter = pAdapterNode->pAdapter;
1962 pScanInfo = &pAdapter->scan_info;
1963
Sandeep Puligillaf8527122016-11-16 18:35:16 -08001964 if (sme_neighbor_middle_of_roaming
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965 (pHddCtx->hHal, pAdapter->sessionId)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001966 hdd_err("Roaming in progress, do not allow suspend");
Dustin Brown105d7902016-10-03 16:27:59 -07001967 wlan_hdd_inc_suspend_stats(pHddCtx,
1968 SUSPEND_FAIL_ROAM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001969 return -EAGAIN;
1970 }
1971
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001972 if (pScanInfo->mScanPending) {
1973 INIT_COMPLETION(pScanInfo->abortscan_event_var);
1974 hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId,
1975 eCSR_SCAN_ABORT_DEFAULT);
1976
1977 status =
1978 wait_for_completion_timeout(&pScanInfo->
1979 abortscan_event_var,
1980 msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN));
1981 if (!status) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001982 hdd_err("Timeout occurred while waiting for abort scan");
Dustin Brown105d7902016-10-03 16:27:59 -07001983 wlan_hdd_inc_suspend_stats(pHddCtx,
1984 SUSPEND_FAIL_SCAN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001985 return -ETIME;
1986 }
1987 }
1988 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1989 pAdapterNode = pNext;
1990 }
1991
1992 /*
1993 * Suspend IPA early before proceeding to suspend other entities like
1994 * firmware to avoid any race conditions.
1995 */
1996 if (hdd_ipa_suspend(pHddCtx)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001997 hdd_err("IPA not ready to suspend!");
Dustin Brown105d7902016-10-03 16:27:59 -07001998 wlan_hdd_inc_suspend_stats(pHddCtx, SUSPEND_FAIL_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001999 return -EAGAIN;
2000 }
2001
2002 /* Wait for the target to be ready for suspend */
2003 INIT_COMPLETION(pHddCtx->ready_to_suspend);
2004
2005 hdd_suspend_wlan(&wlan_hdd_cfg80211_ready_to_suspend, pHddCtx);
2006
2007 rc = wait_for_completion_timeout(&pHddCtx->ready_to_suspend,
2008 msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_SUSPEND));
2009 if (!rc) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002010 hdd_err("Failed to get ready to suspend");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011 goto resume_tx;
2012 }
2013
2014 if (!pHddCtx->suspended) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002015 hdd_err("Faied as suspend_status is wrong:%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002016 pHddCtx->suspended);
2017 goto resume_tx;
2018 }
2019
2020 /* Suspend MC thread */
Krunal Sonid32c6bc2016-10-18 18:00:21 -07002021 scheduler_register_hdd_suspend_callback(hdd_suspend_cb);
2022 scheduler_set_event_mask(MC_SUSPEND_EVENT_MASK);
2023 scheduler_wake_up_controller_thread();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002024
2025 /* Wait for suspend confirmation from MC thread */
2026 rc = wait_for_completion_timeout(&pHddCtx->mc_sus_event_var,
2027 msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
2028 if (!rc) {
Krunal Sonid32c6bc2016-10-18 18:00:21 -07002029 scheduler_clear_event_mask(MC_SUSPEND_EVENT_MASK);
Jeff Johnsonc3273322016-07-06 15:28:17 -07002030 hdd_err("Failed to stop mc thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031 goto resume_tx;
2032 }
2033
2034 pHddCtx->isMcThreadSuspended = true;
2035
2036#ifdef QCA_CONFIG_SMP
2037 /* Suspend tlshim rx thread */
2038 set_bit(RX_SUSPEND_EVENT_MASK, &cds_sched_context->ol_rx_event_flag);
2039 wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue);
2040 rc = wait_for_completion_timeout(&cds_sched_context->
2041 ol_suspend_rx_event,
2042 msecs_to_jiffies
2043 (RX_TLSHIM_SUSPEND_TIMEOUT));
2044 if (!rc) {
2045 clear_bit(RX_SUSPEND_EVENT_MASK,
2046 &cds_sched_context->ol_rx_event_flag);
Jeff Johnsonc3273322016-07-06 15:28:17 -07002047 hdd_err("Failed to stop tl_shim rx thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048 goto resume_all;
2049 }
2050 pHddCtx->is_ol_rx_thread_suspended = true;
2051#endif
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302052 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302053 TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
2054 NO_SESSION, pHddCtx->isWiphySuspended));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 pHddCtx->isWiphySuspended = true;
2056
Yuanyuan Liu13738502016-04-06 17:41:37 -07002057 pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_NONE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002058
2059 EXIT();
2060 return 0;
2061
2062#ifdef QCA_CONFIG_SMP
2063resume_all:
2064
Krunal Sonid32c6bc2016-10-18 18:00:21 -07002065 scheduler_resume_complete();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002066 pHddCtx->isMcThreadSuspended = false;
2067#endif
2068
2069resume_tx:
2070
2071 hdd_resume_wlan();
2072 return -ETIME;
2073
2074}
2075
2076/**
2077 * wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
2078 * @wiphy: Pointer to wiphy
2079 * @wow: Pointer to wow
2080 *
2081 * This API is called when cfg80211 driver suspends
2082 *
2083 * Return: integer status
2084 */
2085int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
2086 struct cfg80211_wowlan *wow)
2087{
2088 int ret;
2089
2090 cds_ssr_protect(__func__);
2091 ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
2092 cds_ssr_unprotect(__func__);
2093
2094 return ret;
2095}
2096
2097/**
Komal Seelama89be8d2016-09-29 11:09:26 +05302098 * hdd_stop_dhcp_ind() - API to stop DHCP sequence
2099 * @adapter: Adapter on which DHCP needs to be stopped
2100 *
2101 * Release the wakelock held for DHCP process and allow
2102 * the runtime pm to continue
2103 *
2104 * Return: None
2105 */
2106static void hdd_stop_dhcp_ind(hdd_adapter_t *adapter)
2107{
2108 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2109
2110 hdd_warn("DHCP stop indicated through power save");
2111 sme_dhcp_stop_ind(hdd_ctx->hHal, adapter->device_mode,
2112 adapter->macAddressCurrent.bytes,
2113 adapter->sessionId);
2114 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
2115 qdf_runtime_pm_allow_suspend(adapter->connect_rpm_ctx.connect);
2116}
2117
2118/**
2119 * hdd_start_dhcp_ind() - API to start DHCP sequence
2120 * @adapter: Adapter on which DHCP needs to be stopped
2121 *
2122 * Prevent APPS suspend and the runtime suspend during
2123 * DHCP sequence
2124 *
2125 * Return: None
2126 */
2127static void hdd_start_dhcp_ind(hdd_adapter_t *adapter)
2128{
2129 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2130
2131 hdd_err("DHCP start indicated through power save");
2132 qdf_runtime_pm_prevent_suspend(adapter->connect_rpm_ctx.connect);
2133 hdd_prevent_suspend_timeout(1000, WIFI_POWER_EVENT_WAKELOCK_DHCP);
2134 sme_dhcp_start_ind(hdd_ctx->hHal, adapter->device_mode,
2135 adapter->macAddressCurrent.bytes,
2136 adapter->sessionId);
2137}
2138
2139/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002140 * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
2141 * @wiphy: Pointer to wiphy
2142 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07002143 * @allow_power_save: is wlan allowed to go into power save mode
2144 * @timeout: Timeout value in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002145 *
2146 * Return: 0 for success, non-zero for failure
2147 */
2148static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07002149 struct net_device *dev,
2150 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002151 int timeout)
2152{
2153 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2154 hdd_context_t *pHddCtx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302155 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002156 int status;
2157
Dustin Brownecfce632016-09-13 10:41:45 -07002158 ENTER();
2159
Dustin Brownf660fb42016-09-09 12:04:00 -07002160 if (timeout < 0) {
2161 hdd_notice("User space timeout: %d; Using default instead: %d",
2162 timeout, AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE);
2163 timeout = AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE;
2164 }
2165
Anurag Chouhan6d760662016-02-20 16:05:43 +05302166 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002167 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002168 return -EINVAL;
2169 }
2170
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302171 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
2172 hdd_err("invalid session id: %d", pAdapter->sessionId);
2173 return -EINVAL;
2174 }
2175
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302176 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002177 TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
2178 pAdapter->sessionId, timeout));
2179
2180 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2181 status = wlan_hdd_validate_context(pHddCtx);
2182
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302183 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002184 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002185
Arun Khandavalli99286452016-08-22 12:13:41 +05302186 mutex_lock(&pHddCtx->iface_change_lock);
2187 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
2188 mutex_unlock(&pHddCtx->iface_change_lock);
2189 hdd_info("Driver Module not enabled return success");
2190 return 0;
2191 }
2192 mutex_unlock(&pHddCtx->iface_change_lock);
2193
Dustin Brownf660fb42016-09-09 12:04:00 -07002194 if (allow_power_save &&
2195 pHddCtx->hdd_wlan_suspended &&
2196 pHddCtx->config->fhostArpOffload &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002197 (eConnectionState_Associated ==
2198 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) {
Dustin Brownf660fb42016-09-09 12:04:00 -07002199 hdd_notice("offload: in cfg80211_set_power_mgmt, "
2200 "calling arp offload");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302201 qdf_status = hdd_conf_arp_offload(pAdapter, true);
2202 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002203 hdd_notice("Failed to enable ARPOFFLOAD Feature %d",
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302204 qdf_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002205 }
2206 }
2207
Dustin Brownf660fb42016-09-09 12:04:00 -07002208 status = wlan_hdd_set_powersave(pAdapter, allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002209
Komal Seelama89be8d2016-09-29 11:09:26 +05302210 allow_power_save ? hdd_stop_dhcp_ind(pAdapter) :
2211 hdd_start_dhcp_ind(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002212
2213 EXIT();
2214 return status;
2215}
2216
2217/**
2218 * wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
2219 * @wiphy: Pointer to wiphy
2220 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07002221 * @allow_power_save: is wlan allowed to go into power save mode
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002222 * @timeout: Timeout value
2223 *
2224 * Return: 0 for success, non-zero for failure
2225 */
2226int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07002227 struct net_device *dev,
2228 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002229 int timeout)
2230{
2231 int ret;
2232
2233 cds_ssr_protect(__func__);
Dustin Brownf660fb42016-09-09 12:04:00 -07002234 ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev,
2235 allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002236 cds_ssr_unprotect(__func__);
2237
2238 return ret;
2239}
2240
2241/**
2242 * __wlan_hdd_cfg80211_set_txpower() - set TX power
2243 * @wiphy: Pointer to wiphy
2244 * @wdev: Pointer to network device
2245 * @type: TX power setting type
2246 * @dbm: TX power in dbm
2247 *
2248 * Return: 0 for success, non-zero for failure
2249 */
2250static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002251 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002252 enum nl80211_tx_power_setting type,
2253 int dbm)
2254{
2255 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
2256 tHalHandle hHal = NULL;
Anurag Chouhan6d760662016-02-20 16:05:43 +05302257 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
2258 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002259 int status;
2260
2261 ENTER();
2262
Anurag Chouhan6d760662016-02-20 16:05:43 +05302263 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002264 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002265 return -EINVAL;
2266 }
2267
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302268 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002269 TRACE_CODE_HDD_CFG80211_SET_TXPOWER,
2270 NO_SESSION, type));
2271
2272 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302273 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002274 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002275
2276 hHal = pHddCtx->hHal;
2277
2278 if (0 != sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, dbm)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002279 hdd_err("sme_cfg_set_int failed for tx power %hu",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002280 dbm);
2281 return -EIO;
2282 }
2283
Jeff Johnsonc3273322016-07-06 15:28:17 -07002284 hdd_info("Set tx power level %d dbm", dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002285
2286 switch (type) {
2287 /* Automatically determine transmit power */
2288 case NL80211_TX_POWER_AUTOMATIC:
2289 /* Fall through */
2290 case NL80211_TX_POWER_LIMITED: /* Limit TX power by the mBm parameter */
2291 if (sme_set_max_tx_power(hHal, bssid, selfMac, dbm) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302292 QDF_STATUS_SUCCESS) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002293 hdd_err("Setting maximum tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002294 return -EIO;
2295 }
2296 break;
2297
2298 case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */
Jeff Johnsonc3273322016-07-06 15:28:17 -07002299 hdd_err("NL80211_TX_POWER_FIXED not supported");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002300 return -EOPNOTSUPP;
2301 break;
2302
2303 default:
Jeff Johnsonc3273322016-07-06 15:28:17 -07002304 hdd_err("Invalid power setting type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002305 return -EIO;
2306 }
2307
2308 EXIT();
2309 return 0;
2310}
2311
2312/**
2313 * wlan_hdd_cfg80211_set_txpower() - set TX power
2314 * @wiphy: Pointer to wiphy
2315 * @wdev: Pointer to network device
2316 * @type: TX power setting type
2317 * @dbm: TX power in dbm
2318 *
2319 * Return: 0 for success, non-zero for failure
2320 */
2321int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002322 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002323 enum nl80211_tx_power_setting type,
2324 int dbm)
2325{
2326 int ret;
2327 cds_ssr_protect(__func__);
2328 ret = __wlan_hdd_cfg80211_set_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002330 type, dbm);
2331 cds_ssr_unprotect(__func__);
2332
2333 return ret;
2334}
2335
2336/**
2337 * __wlan_hdd_cfg80211_get_txpower() - get TX power
2338 * @wiphy: Pointer to wiphy
2339 * @wdev: Pointer to network device
2340 * @dbm: Pointer to TX power in dbm
2341 *
2342 * Return: 0 for success, non-zero for failure
2343 */
2344static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002345 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002346 int *dbm)
2347{
2348
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002349 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
Arun Khandavalli99286452016-08-22 12:13:41 +05302350 struct net_device *ndev = wdev->netdev;
2351 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002352 int status;
2353
2354 ENTER();
2355
Anurag Chouhan6d760662016-02-20 16:05:43 +05302356 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002357 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002358 return -EINVAL;
2359 }
2360
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302361 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2362 hdd_err("invalid session id: %d", adapter->sessionId);
2363 return -EINVAL;
2364 }
2365
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002366 status = wlan_hdd_validate_context(pHddCtx);
2367 if (0 != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002368 *dbm = 0;
2369 return status;
2370 }
2371
Arun Khandavalli99286452016-08-22 12:13:41 +05302372 if (!adapter) {
2373 hdd_err("adapter is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002374 return -ENOENT;
2375 }
2376
Arun Khandavalli99286452016-08-22 12:13:41 +05302377 /* Validate adapter sessionId */
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302378 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2379 hdd_err("invalid session id: %d", adapter->sessionId);
Arun Khandavalli99286452016-08-22 12:13:41 +05302380 return -ENOTSUPP;
2381 }
2382
2383 mutex_lock(&pHddCtx->iface_change_lock);
2384 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
2385 mutex_unlock(&pHddCtx->iface_change_lock);
2386 hdd_info("Driver Module not enabled return success");
2387 /* Send cached data to upperlayer*/
2388 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
2389 return 0;
2390 }
2391 mutex_unlock(&pHddCtx->iface_change_lock);
2392
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302393 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302394 TRACE_CODE_HDD_CFG80211_GET_TXPOWER,
Arun Khandavalli99286452016-08-22 12:13:41 +05302395 adapter->sessionId, adapter->device_mode));
2396 wlan_hdd_get_class_astats(adapter);
2397 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002398
2399 EXIT();
2400 return 0;
2401}
2402
2403/**
2404 * wlan_hdd_cfg80211_get_txpower() - cfg80211 get power handler function
2405 * @wiphy: Pointer to wiphy structure.
2406 * @wdev: Pointer to wireless_dev structure.
2407 * @dbm: dbm
2408 *
2409 * This is the cfg80211 get txpower handler function which invokes
2410 * the internal function @__wlan_hdd_cfg80211_get_txpower with
2411 * SSR protection.
2412 *
2413 * Return: 0 for success, error number on failure.
2414 */
2415int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002416 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002417 int *dbm)
2418{
2419 int ret;
2420
2421 cds_ssr_protect(__func__);
2422 ret = __wlan_hdd_cfg80211_get_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002423 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002424 dbm);
2425 cds_ssr_unprotect(__func__);
2426
2427 return ret;
2428}
Kapil Gupta6213c012016-09-02 19:39:09 +05302429
2430/**
2431 * hdd_set_qpower_config() - set qpower config to firmware
2432 * @adapter: HDD adapter
2433 * @qpower: new qpower config value
2434 *
2435 * Return: 0 on success; Errno on failure
2436 */
2437int hdd_set_qpower_config(hdd_context_t *hddctx, hdd_adapter_t *adapter,
Dustin Brown10a7b712016-10-07 10:31:16 -07002438 u8 qpower)
Kapil Gupta6213c012016-09-02 19:39:09 +05302439{
Dustin Brown10a7b712016-10-07 10:31:16 -07002440 QDF_STATUS status;
Kapil Gupta6213c012016-09-02 19:39:09 +05302441
2442 if (!hddctx->config->enablePowersaveOffload) {
2443 hdd_err("qpower is disabled in configuration");
2444 return -EINVAL;
2445 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002446
Kapil Gupta6213c012016-09-02 19:39:09 +05302447 if (qpower > PS_DUTY_CYCLING_QPOWER ||
2448 qpower < PS_LEGACY_NODEEPSLEEP) {
Dustin Brown10a7b712016-10-07 10:31:16 -07002449 hdd_err("invalid qpower value: %d", qpower);
Kapil Gupta6213c012016-09-02 19:39:09 +05302450 return -EINVAL;
2451 }
Kapil Gupta6213c012016-09-02 19:39:09 +05302452
Dustin Brown10a7b712016-10-07 10:31:16 -07002453 status = wma_set_qpower_config(adapter->sessionId, qpower);
2454 if (status != QDF_STATUS_SUCCESS) {
2455 hdd_err("failed to configure qpower: %d", status);
2456 return -EINVAL;
Kapil Gupta6213c012016-09-02 19:39:09 +05302457 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002458
Kapil Gupta6213c012016-09-02 19:39:09 +05302459 return 0;
2460}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002461
2462#ifdef WLAN_SUSPEND_RESUME_TEST
2463/*
Dustin Brownd53d1a82016-10-03 12:57:33 -07002464 * On iHelium there are 12 CE irqs and #2 is the wake irq. This may not be
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002465 * a valid assumption on future platforms.
2466 */
2467#define CE_IRQ_COUNT 12
2468#define CE_WAKE_IRQ 2
Dustin Brownbc81a472016-10-26 16:56:59 -07002469static struct net_device *g_dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002470static struct wiphy *g_wiphy;
2471
2472#define HDD_FA_SUSPENDED_BIT (0)
2473static unsigned long fake_apps_state;
2474
Dustin Brownd53d1a82016-10-03 12:57:33 -07002475/**
2476 * __hdd_wlan_fake_apps_resume() - The core logic for
2477 * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(),
2478 * which is only need for non-irq resume
Dustin Brownbc81a472016-10-26 16:56:59 -07002479 * @wiphy: the kernel wiphy struct for the device being resumed
2480 * @dev: the kernel net_device struct for the device being resumed
Dustin Brownd53d1a82016-10-03 12:57:33 -07002481 *
Dustin Brownbc81a472016-10-26 16:56:59 -07002482 * Return: none, calls QDF_BUG() on failure
Dustin Brownd53d1a82016-10-03 12:57:33 -07002483 */
Dustin Brownbc81a472016-10-26 16:56:59 -07002484static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy,
2485 struct net_device *dev)
Dustin Brownd53d1a82016-10-03 12:57:33 -07002486{
2487 qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2488 int i, resume_err;
2489
2490 hdd_info("Unit-test resume WLAN");
2491 if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
2492 hdd_info("Not unit-test suspended; Nothing to do");
2493 return;
2494 }
2495
2496 /* disable wake irq */
2497 pld_disable_irq(qdf_dev->dev, CE_WAKE_IRQ);
2498
2499 resume_err = wlan_hdd_bus_resume_noirq();
2500 QDF_BUG(resume_err == 0);
2501
2502 /* simulate kernel enable irqs */
2503 for (i = 0; i < CE_IRQ_COUNT; i++)
2504 pld_enable_irq(qdf_dev->dev, i);
2505
2506 resume_err = wlan_hdd_bus_resume();
2507 QDF_BUG(resume_err == 0);
2508
2509 resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy);
2510 QDF_BUG(resume_err == 0);
Dustin Brownbc81a472016-10-26 16:56:59 -07002511
2512 dev->watchdog_timeo = HDD_TX_TIMEOUT;
Dustin Brownd53d1a82016-10-03 12:57:33 -07002513}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002514
2515/**
2516 * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming
2517 * from unit-test initiated suspend from irq wakeup signal
2518 * @val: interrupt val
2519 *
2520 * Resume wlan after getting very 1st CE interrupt from target
2521 *
2522 * Return: none
2523 */
2524static void hdd_wlan_fake_apps_resume_irq_callback(uint32_t val)
2525{
2526 hdd_info("Trigger unit-test resume WLAN; val: 0x%x", val);
2527
2528 QDF_BUG(g_wiphy);
Dustin Brownbc81a472016-10-26 16:56:59 -07002529 QDF_BUG(g_dev);
2530 __hdd_wlan_fake_apps_resume(g_wiphy, g_dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002531 g_wiphy = NULL;
Dustin Brownbc81a472016-10-26 16:56:59 -07002532 g_dev = NULL;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002533}
2534
Dustin Brownbc81a472016-10-26 16:56:59 -07002535int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002536{
2537 qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2538 struct hif_opaque_softc *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2539 pm_message_t state;
2540 int i, resume_err, suspend_err;
2541
2542 hdd_info("Unit-test suspend WLAN");
2543 if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
2544 hdd_info("Already unit-test suspended; Nothing to do");
2545 return 0;
2546 }
2547
2548 suspend_err = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL);
2549 if (suspend_err)
2550 goto resume_done;
2551
2552 state.event = PM_EVENT_SUSPEND;
Dustin Browne70fd972016-11-10 11:17:40 -08002553 suspend_err = wlan_hdd_unit_test_bus_suspend(state);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002554 if (suspend_err)
2555 goto cfg80211_resume;
2556
2557 /* simulate kernel disabling irqs */
2558 for (i = 0; i < CE_IRQ_COUNT; i++)
2559 pld_disable_irq(qdf_dev->dev, i);
2560
2561 suspend_err = wlan_hdd_bus_suspend_noirq();
2562 if (suspend_err)
2563 goto enable_irqs_and_bus_resume;
2564
2565 /* re-enable wake irq */
2566 pld_enable_irq(qdf_dev->dev, CE_WAKE_IRQ);
2567
Dustin Brownbc81a472016-10-26 16:56:59 -07002568 /* pass wiphy/dev to callback via global variables */
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002569 g_wiphy = wiphy;
Dustin Brownbc81a472016-10-26 16:56:59 -07002570 g_dev = dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002571 hif_fake_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback);
2572
Dustin Brownbc81a472016-10-26 16:56:59 -07002573 /*
2574 * Tell the kernel not to worry if TX queues aren't moving. This is
2575 * expected since we are suspending the wifi hardware, but not APPS
2576 */
2577 dev->watchdog_timeo = INT_MAX;
2578
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002579 return 0;
2580
2581enable_irqs_and_bus_resume:
2582 /* re-enable irqs */
2583 for (i = 0; i < CE_IRQ_COUNT; i++)
2584 pld_enable_irq(qdf_dev->dev, i);
2585
2586 resume_err = wlan_hdd_bus_resume();
2587 QDF_BUG(resume_err == 0);
2588
2589cfg80211_resume:
2590 resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy);
2591 QDF_BUG(resume_err == 0);
2592
2593resume_done:
2594 clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state);
2595 hdd_err("Unit-test suspend failed: %d", suspend_err);
2596 return suspend_err;
2597}
2598
Dustin Brownbc81a472016-10-26 16:56:59 -07002599int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002600{
2601 struct hif_opaque_softc *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002602
2603 hif_fake_apps_resume(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002604 __hdd_wlan_fake_apps_resume(wiphy, dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002605
2606 return 0;
2607}
2608#endif