blob: ee3eed420a1afaf24a19356cb8fd637ea74288e1 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Poddar, Siddartha78cac32016-12-29 20:08:34 +05302 * Copyright (c) 2012-2017 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>
Poddar, Siddartha78cac32016-12-29 20:08:34 +053073#include <ol_txrx_osif_api.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080074#include "hif.h"
75#include "sme_power_save_api.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080076#include "wlan_policy_mgr_api.h"
Dhanashri Atreb08959a2016-03-01 17:28:03 -080077#include "cdp_txrx_flow_ctrl_v2.h"
Yuanyuan Liu13738502016-04-06 17:41:37 -070078#include "pld_common.h"
Rajeev Kumar9bb2e852016-09-24 12:29:25 -070079#include "wlan_hdd_driver_ops.h"
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +053080#include <wlan_logging_sock_svc.h>
Krunal Sonid32c6bc2016-10-18 18:00:21 -070081#include "scheduler_api.h"
yeshwanth sriram guntuka310b3ac2016-11-15 23:25:26 +053082#include "cds_utils.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080083
84/* Preprocessor definitions and constants */
Yue Ma4ea4f052015-10-27 12:25:27 -070085#define HDD_SSR_BRING_UP_TIME 30000
Sreelakshmi Konamki22528532016-09-06 16:34:50 +053086#define HDD_WAKE_LOCK_RESUME_DURATION 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080087
88/* Type declarations */
89
Abhishek Singhbaea27d2016-04-27 13:29:30 +053090#ifdef FEATURE_WLAN_DIAG_SUPPORT
91/**
92 * hdd_wlan_suspend_resume_event()- send suspend/resume state
93 * @state: suspend/resume state
94 *
95 * This Function send send suspend resume state diag event
96 *
97 * Return: void.
98 */
99void hdd_wlan_suspend_resume_event(uint8_t state)
100{
101 WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend);
102 qdf_mem_zero(&suspend_state, sizeof(suspend_state));
103
104 suspend_state.state = state;
105 WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
106}
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530107
108/**
109 * hdd_wlan_offload_event()- send offloads event
110 * @type: offload type
111 * @state: enabled or disabled
112 *
113 * This Function send offloads enable/disable diag event
114 *
115 * Return: void.
116 */
117
118void hdd_wlan_offload_event(uint8_t type, uint8_t state)
119{
120 WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req);
121 qdf_mem_zero(&host_offload, sizeof(host_offload));
122
123 host_offload.offload_type = type;
124 host_offload.state = state;
125
126 WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ);
127}
Abhishek Singhbaea27d2016-04-27 13:29:30 +0530128#endif
129
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800130/* Function and variables declarations */
131
132extern struct notifier_block hdd_netdev_notifier;
133
134static struct timer_list ssr_timer;
135static bool ssr_timer_started;
Mukul Sharma3d36c392017-01-18 18:39:12 +0530136
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800137/**
Mukul Sharma3d36c392017-01-18 18:39:12 +0530138 * hdd_enable_gtk_offload() - enable GTK offload
139 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140 *
Mukul Sharma3d36c392017-01-18 18:39:12 +0530141 * Central function to enable GTK offload.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800142 *
143 * Return: nothing
144 */
Mukul Sharma3d36c392017-01-18 18:39:12 +0530145static void hdd_enable_gtk_offload(hdd_adapter_t *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800146{
Mukul Sharma3d36c392017-01-18 18:39:12 +0530147 QDF_STATUS status;
148 status = pmo_ucfg_enable_gtk_offload_in_fwr(adapter->hdd_vdev);
149 if (status != QDF_STATUS_SUCCESS)
150 hdd_info("Failed to enable gtk offload");
151}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800152
Mukul Sharma3d36c392017-01-18 18:39:12 +0530153/**
154 * hdd_disable_gtk_offload() - disable GTK offload
155 * @pAdapter: pointer to the adapter
156 *
157 * Central function to disable GTK offload.
158 *
159 * Return: nothing
160 */
161static void hdd_disable_gtk_offload(hdd_adapter_t *adapter)
162{
163 struct pmo_gtk_rsp_req gtk_rsp_request;
164 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165
Mukul Sharma3d36c392017-01-18 18:39:12 +0530166 /* ensure to get gtk rsp first before disable it*/
167 gtk_rsp_request.callback =
168 wlan_hdd_cfg80211_update_replay_counter_callback;
169 /* Passing as void* as PMO does not know legacy HDD adapter type */
170 gtk_rsp_request.callback_context =
171 (void *)adapter;
172 status = pmo_ucfg_get_gtk_rsp(adapter->hdd_vdev,
173 &gtk_rsp_request);
174 if (status != QDF_STATUS_SUCCESS) {
175 hdd_err("Failed to send get gtk rsp status:%d", status);
176 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800177 }
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800178 hdd_debug("send get_gtk_rsp successful");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530179 status = pmo_ucfg_disable_gtk_offload_in_fwr(adapter->hdd_vdev);
180 if (status != QDF_STATUS_SUCCESS)
181 hdd_info("Failed to disable gtk offload");
182
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800183}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530185
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800186/**
187 * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function
188 * @nb: notifier block that was registered with the kernel
189 * @data: (unused) generic data that was registered with the kernel
190 * @arg: (unused) generic argument that was registered with the kernel
191 *
192 * This is a callback function that is registered with the kernel via
193 * register_inet6addr_notifier() which allows the driver to be
194 * notified when there is an IPv6 address change.
195 *
196 * Return: NOTIFY_DONE to indicate we don't care what happens with
197 * other callbacks
198 */
199static int __wlan_hdd_ipv6_changed(struct notifier_block *nb,
200 unsigned long data, void *arg)
201{
202 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
203 struct net_device *ndev = ifa->idev->dev;
204 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
205 hdd_context_t *pHddCtx;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700206 hdd_station_ctx_t *sta_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207 int status;
208
Jeff Johnson158c8d02016-10-31 13:11:48 -0700209 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530210
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211 if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700212 hdd_err("Adapter context is invalid %p", pAdapter);
Jeff Johnson158c8d02016-10-31 13:11:48 -0700213 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800214 }
215
216 if ((pAdapter->dev == ndev) &&
Jeff Johnson158c8d02016-10-31 13:11:48 -0700217 (pAdapter->device_mode == QDF_STA_MODE ||
218 pAdapter->device_mode == QDF_P2P_CLIENT_MODE ||
219 pAdapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800220 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
221 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530222 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800223 return NOTIFY_DONE;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700224 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Padma, Santhosh Kumar8392fb42017-03-17 12:35:27 +0530225 hdd_debug("invoking sme_dhcp_done_ind");
226 sme_dhcp_done_ind(pHddCtx->hHal,
Jeff Johnson158c8d02016-10-31 13:11:48 -0700227 pAdapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800228 schedule_work(&pAdapter->ipv6NotifierWorkQueue);
229 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530230 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800231 return NOTIFY_DONE;
232}
233
234/**
235 * wlan_hdd_ipv6_changed() - IPv6 change notifier callback
236 * @nb: pointer to notifier block
237 * @data: data
238 * @arg: arg
239 *
240 * This is the IPv6 notifier callback function gets invoked
241 * if any change in IP and then invoke the function @__wlan_hdd_ipv6_changed
242 * to reconfigure the offload parameters.
243 *
244 * Return: 0 on success, error number otherwise.
245 */
246int wlan_hdd_ipv6_changed(struct notifier_block *nb,
247 unsigned long data, void *arg)
248{
249 int ret;
250
251 cds_ssr_protect(__func__);
252 ret = __wlan_hdd_ipv6_changed(nb, data, arg);
253 cds_ssr_unprotect(__func__);
254
255 return ret;
256}
257
258/**
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530259 * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses
260 * @idev: pointer to net device
261 * @ipv6addr: destination array to fill IPv6 addresses
262 * @ipv6addr_type: IPv6 Address type
263 * @count: number of IPv6 addresses
264 *
265 * This is the IPv6 utility function to populate unicast addresses.
266 *
267 * Return: 0 on success, error number otherwise.
268 */
269static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
270 uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN],
271 uint8_t *ipv6addr_type, uint32_t *count)
272{
273 struct inet6_ifaddr *ifa;
274 struct list_head *p;
275 uint32_t scope;
276
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700277 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530278 list_for_each(p, &idev->addr_list) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530279 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700280 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530281 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700282 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530283 ifa = list_entry(p, struct inet6_ifaddr, if_list);
284 if (ifa->flags & IFA_F_DADFAILED)
285 continue;
286 scope = ipv6_addr_src_scope(&ifa->addr);
287 switch (scope) {
288 case IPV6_ADDR_SCOPE_GLOBAL:
289 case IPV6_ADDR_SCOPE_LINKLOCAL:
290 qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
291 sizeof(ifa->addr.s6_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530292 ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE;
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800293 hdd_debug("Index %d scope = %s UC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530294 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
295 "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
296 *count += 1;
297 break;
298 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800299 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530300 }
301 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700302
303 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530304 return 0;
305}
306
307/**
308 * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses
309 * @idev: pointer to net device
310 * @ipv6addr: destination array to fill IPv6 addresses
311 * @ipv6addr_type: IPv6 Address type
312 * @count: number of IPv6 addresses
313 *
314 * This is the IPv6 utility function to populate anycast addresses.
315 *
316 * Return: 0 on success, error number otherwise.
317 */
318static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
319 uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN],
320 uint8_t *ipv6addr_type, uint32_t *count)
321{
322 struct ifacaddr6 *ifaca;
323 uint32_t scope;
324
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700325 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530326 for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530327 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700328 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530329 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700330 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530331 /* For anycast addr no DAD */
332 scope = ipv6_addr_src_scope(&ifaca->aca_addr);
333 switch (scope) {
334 case IPV6_ADDR_SCOPE_GLOBAL:
335 case IPV6_ADDR_SCOPE_LINKLOCAL:
336 qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
337 sizeof(ifaca->aca_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530338 ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE;
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800339 hdd_debug("Index %d scope = %s AC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530340 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
341 "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
342 *count += 1;
343 break;
344 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800345 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530346 }
347 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700348
349 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530350 return 0;
351}
352
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530353void hdd_enable_ns_offload(hdd_adapter_t *adapter,
354 enum pmo_offload_trigger trigger)
Dustin Brown2444ee62016-09-06 17:20:36 -0700355{
356 struct inet6_dev *in6_dev;
Dustin Brown2444ee62016-09-06 17:20:36 -0700357 QDF_STATUS status;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530358 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
359 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
360 struct pmo_ns_req *ns_req = NULL;
361 int err;
362
363 ENTER();
364 if (!psoc) {
365 hdd_err("psoc is NULL");
366 goto out;
367 }
Dustin Brown2444ee62016-09-06 17:20:36 -0700368
369 in6_dev = __in6_dev_get(adapter->dev);
370 if (NULL == in6_dev) {
371 hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530372 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700373 }
374
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530375 ns_req = qdf_mem_malloc(sizeof(*ns_req));
376 if (!ns_req) {
377 hdd_err("fail to allocate ns_req");
378 goto out;
379 }
380
381 ns_req->psoc = psoc;
382 ns_req->vdev_id = adapter->sessionId;
383 ns_req->trigger = trigger;
384 ns_req->count = 0;
385
Dustin Brown2444ee62016-09-06 17:20:36 -0700386 /* Unicast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530387 err = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
388 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700389 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530390 hdd_disable_ns_offload(adapter, trigger);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800391 hdd_debug("Reached max supported addresses and not enabling "
Dustin Brown2444ee62016-09-06 17:20:36 -0700392 "NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530393 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700394 }
395
396 /* Anycast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530397 err = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
398 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700399 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530400 hdd_disable_ns_offload(adapter, trigger);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800401 hdd_debug("Reached max supported addresses and not enabling "
Dustin Brown2444ee62016-09-06 17:20:36 -0700402 "NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530403 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700404 }
405
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530406 /* cache ns request */
407 status = pmo_ucfg_cache_ns_offload_req(ns_req);
408 if (status != QDF_STATUS_SUCCESS) {
409 hdd_err("Failed to cache ns request status: %d", status);
410 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700411 }
412
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530413 /* enable ns request */
414 status = pmo_ucfg_enable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
415 if (status != QDF_STATUS_SUCCESS)
Dustin Brown2444ee62016-09-06 17:20:36 -0700416 hdd_err("Failed to enable HostOffload feature with status: %d",
417 status);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530418 else
419 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
420out:
421 if (ns_req)
422 qdf_mem_free(ns_req);
423 EXIT();
424
Dustin Brown2444ee62016-09-06 17:20:36 -0700425}
426
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530427void hdd_disable_ns_offload(hdd_adapter_t *adapter,
428 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800429{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530430 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800431
432 ENTER();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530433 status = pmo_ucfg_flush_ns_offload_req(adapter->hdd_vdev);
434 if (status != QDF_STATUS_SUCCESS) {
435 hdd_err("Failed to flush NS Offload");
436 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800437 }
438
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530439 status = pmo_ucfg_disable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
440 if (status != QDF_STATUS_SUCCESS)
441 hdd_err("Failed to disable NS Offload");
Dustin Brown2444ee62016-09-06 17:20:36 -0700442 else
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530443 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD,
444 SIR_OFFLOAD_DISABLE);
445out:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800446 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530447
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800448}
449
450/**
451 * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function
452 * @work: registered work item
453 *
454 * This function performs the work initially trigged by a callback
455 * from the IPv6 netdev notifier. Since this means there has been a
456 * change in IPv6 state for the interface, the NS offload is
457 * reconfigured.
458 *
459 * Return: None
460 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700461static void __hdd_ipv6_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800462{
463 hdd_adapter_t *pAdapter =
464 container_of(work, hdd_adapter_t, ipv6NotifierWorkQueue);
465 hdd_context_t *pHddCtx;
466 int status;
467
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530468 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800469
470 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
471 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530472 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800473 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530475 hdd_enable_ns_offload(pAdapter, pmo_ipv6_change_notify);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530476 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800477}
478
479/**
480 * hdd_ipv6_notifier_work_queue() - IP V6 change notifier work handler
481 * @work: Pointer to work context
482 *
483 * Return: none
484 */
485void hdd_ipv6_notifier_work_queue(struct work_struct *work)
486{
487 cds_ssr_protect(__func__);
488 __hdd_ipv6_notifier_work_queue(work);
489 cds_ssr_unprotect(__func__);
490}
491
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530492void hdd_enable_host_offloads(hdd_adapter_t *adapter,
493 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800494{
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530495 ENTER();
496
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530497 if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
498 hdd_info("offload is not supported on this vdev opmode: %d",
499 adapter->device_mode);
500 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800501 }
502
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530503 if (!pmo_ucfg_is_vdev_connected(adapter->hdd_vdev)) {
504 hdd_info("vdev is not connected");
505 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800506 }
507
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530508 hdd_info("enable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530509 hdd_enable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530510 hdd_enable_arp_offload(adapter, trigger);
511 hdd_enable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530512 hdd_enable_mc_addr_filtering(adapter, trigger);
Ravi Kumar Bokka794fd712017-03-21 20:52:46 +0530513 hdd_enable_non_arp_hw_broadcast_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530514out:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530515 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530516
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800517}
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530518
519void hdd_disable_host_offloads(hdd_adapter_t *adapter,
520 enum pmo_offload_trigger trigger)
521{
522 ENTER();
523
524 if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
525 hdd_info("offload is not supported on this vdev opmode: %d",
526 adapter->device_mode);
527 goto out;
528 }
529
530 if (!pmo_ucfg_is_vdev_connected(adapter->hdd_vdev)) {
531 hdd_info("vdev is not connected");
532 goto out;
533 }
534
535 hdd_info("disable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530536 hdd_disable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530537 hdd_disable_arp_offload(adapter, trigger);
538 hdd_disable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530539 hdd_disable_mc_addr_filtering(adapter, trigger);
Ravi Kumar Bokka794fd712017-03-21 20:52:46 +0530540 hdd_disable_non_arp_hw_broadcast_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530541out:
542 EXIT();
543
544}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800545
546/**
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800547 * hdd_lookup_ifaddr() - Lookup interface address data by name
548 * @adapter: the adapter whose name should be searched for
549 *
550 * return in_ifaddr pointer on success, NULL for failure
551 */
552static struct in_ifaddr *hdd_lookup_ifaddr(hdd_adapter_t *adapter)
553{
554 struct in_ifaddr *ifa;
555 struct in_device *in_dev;
556
557 if (!adapter) {
558 hdd_err("adapter is null");
559 return NULL;
560 }
561
562 in_dev = __in_dev_get_rtnl(adapter->dev);
563 if (!in_dev) {
564 hdd_err("Failed to get in_device");
565 return NULL;
566 }
567
568 /* lookup address data by interface name */
569 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
570 if (!strcmp(adapter->dev->name, ifa->ifa_label))
571 return ifa;
572 }
573
574 return NULL;
575}
576
577/**
578 * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address
579 * @adapter: the adapter whose IPv4 address is desired
580 * @ipv4_addr: the address of the array to copy the IPv4 address into
581 *
582 * return: zero for success; non-zero for failure
583 */
584static int hdd_populate_ipv4_addr(hdd_adapter_t *adapter, uint8_t *ipv4_addr)
585{
586 struct in_ifaddr *ifa;
587 int i;
588
589 if (!adapter) {
590 hdd_err("adapter is null");
591 return -EINVAL;
592 }
593
594 if (!ipv4_addr) {
595 hdd_err("ipv4_addr is null");
596 return -EINVAL;
597 }
598
599 ifa = hdd_lookup_ifaddr(adapter);
600 if (!ifa || !ifa->ifa_local) {
601 hdd_err("ipv4 address not found");
602 return -EINVAL;
603 }
604
605 /* convert u32 to byte array */
606 for (i = 0; i < 4; i++)
607 ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff;
608
609 return 0;
610}
611
612/**
613 * hdd_set_grat_arp_keepalive() - Enable grat APR keepalive
614 * @adapter: the HDD adapter to configure
615 *
616 * This configures gratuitous APR keepalive based on the adapter's current
617 * connection information, specifically IPv4 address and BSSID
618 *
619 * return: zero for success, non-zero for failure
620 */
621static int hdd_set_grat_arp_keepalive(hdd_adapter_t *adapter)
622{
623 QDF_STATUS status;
624 int exit_code;
625 hdd_context_t *hdd_ctx;
626 hdd_station_ctx_t *sta_ctx;
627 tSirKeepAliveReq req = {
628 .packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP,
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800629 .dest_macaddr = QDF_MAC_ADDR_BROADCAST_INITIALIZER,
630 };
631
632 if (!adapter) {
633 hdd_err("adapter is null");
634 return -EINVAL;
635 }
636
637 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
638 if (!hdd_ctx) {
639 hdd_err("hdd_ctx is null");
640 return -EINVAL;
641 }
642
643 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
644 if (!sta_ctx) {
645 hdd_err("sta_ctx is null");
646 return -EINVAL;
647 }
648
649 exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr);
650 if (exit_code) {
651 hdd_err("Failed to populate ipv4 address");
652 return exit_code;
653 }
654
Dustin Brown6b4643d2017-02-09 12:19:28 -0800655 /* according to RFC5227, sender/target ip address should be the same */
656 qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr,
657 sizeof(req.destIpv4Addr));
658
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800659 qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssId);
660 req.timePeriod = hdd_ctx->config->infraStaKeepAlivePeriod;
661 req.sessionId = adapter->sessionId;
662
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800663 hdd_debug("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u",
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800664 req.hostIpv4Addr[0], req.hostIpv4Addr[1],
665 req.hostIpv4Addr[2], req.hostIpv4Addr[3]);
666
667 status = sme_set_keep_alive(hdd_ctx->hHal, req.sessionId, &req);
668 if (QDF_IS_STATUS_ERROR(status)) {
669 hdd_err("Failed to set keepalive");
670 return qdf_status_to_os_return(status);
671 }
672
673 return 0;
674}
675
676/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800677 * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function
678 * @work: registered work item
679 *
680 * This function performs the work initially trigged by a callback
681 * from the IPv4 netdev notifier. Since this means there has been a
682 * change in IPv4 state for the interface, the ARP offload is
683 * reconfigured.
684 *
685 * Return: None
686 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700687static void __hdd_ipv4_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800688{
Dustin Brownb6b0f182017-03-08 13:08:27 -0800689 hdd_adapter_t *adapter;
690 hdd_context_t *hdd_ctx;
691
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530692 ENTER();
Dustin Brownb6b0f182017-03-08 13:08:27 -0800693
694 adapter = container_of(work, hdd_adapter_t, ipv4NotifierWorkQueue);
695 hdd_enable_arp_offload(adapter, pmo_ipv4_change_notify);
696
697 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
698 if (hdd_ctx->config->sta_keepalive_method == HDD_STA_KEEPALIVE_GRAT_ARP)
699 hdd_set_grat_arp_keepalive(adapter);
700
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530701 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800702}
703
704/**
705 * hdd_ipv4_notifier_work_queue() - IP V4 change notifier work handler
706 * @work: Pointer to work context
707 *
708 * Return: none
709 */
710void hdd_ipv4_notifier_work_queue(struct work_struct *work)
711{
712 cds_ssr_protect(__func__);
713 __hdd_ipv4_notifier_work_queue(work);
714 cds_ssr_unprotect(__func__);
715}
716
717/**
718 * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function
719 * @nb: notifier block that was registered with the kernel
720 * @data: (unused) generic data that was registered with the kernel
721 * @arg: (unused) generic argument that was registered with the kernel
722 *
723 * This is a callback function that is registered with the kernel via
724 * register_inetaddr_notifier() which allows the driver to be
725 * notified when there is an IPv4 address change.
726 *
727 * Return: NOTIFY_DONE to indicate we don't care what happens with
728 * other callbacks
729 */
730static int __wlan_hdd_ipv4_changed(struct notifier_block *nb,
731 unsigned long data, void *arg)
732{
733 struct in_ifaddr *ifa = (struct in_ifaddr *)arg;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800734 struct net_device *ndev = ifa->ifa_dev->dev;
735 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
736 hdd_context_t *pHddCtx;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700737 hdd_station_ctx_t *sta_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800738 int status;
739
Jeff Johnson158c8d02016-10-31 13:11:48 -0700740 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530741
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800742 if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700743 hdd_err("Adapter context is invalid %p", pAdapter);
Jeff Johnson158c8d02016-10-31 13:11:48 -0700744 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800745 }
746
Jeff Johnson158c8d02016-10-31 13:11:48 -0700747 if ((pAdapter->dev == ndev) &&
748 (pAdapter->device_mode == QDF_STA_MODE ||
749 pAdapter->device_mode == QDF_P2P_CLIENT_MODE ||
750 pAdapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800751
752 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
753 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530754 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800755 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800756
Jeff Johnson158c8d02016-10-31 13:11:48 -0700757 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Padma, Santhosh Kumar8392fb42017-03-17 12:35:27 +0530758 hdd_debug("invoking sme_dhcp_done_ind");
759 sme_dhcp_done_ind(pHddCtx->hHal,
Jeff Johnson158c8d02016-10-31 13:11:48 -0700760 pAdapter->sessionId);
Abhishek Singhca408032016-09-13 15:26:12 +0530761
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800762 if (!pHddCtx->config->fhostArpOffload) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800763 hdd_debug("Offload not enabled ARPOffload=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800764 pHddCtx->config->fhostArpOffload);
765 return NOTIFY_DONE;
766 }
767
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800768 ifa = hdd_lookup_ifaddr(pAdapter);
769 if (ifa && ifa->ifa_local)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800770 schedule_work(&pAdapter->ipv4NotifierWorkQueue);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800771 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530772 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800773 return NOTIFY_DONE;
774}
775
776/**
777 * wlan_hdd_ipv4_changed() - IPv4 change notifier callback
778 * @nb: pointer to notifier block
779 * @data: data
780 * @arg: arg
781 *
782 * This is the IPv4 notifier callback function gets invoked
783 * if any change in IP and then invoke the function @__wlan_hdd_ipv4_changed
784 * to reconfigure the offload parameters.
785 *
786 * Return: 0 on success, error number otherwise.
787 */
788int wlan_hdd_ipv4_changed(struct notifier_block *nb,
789 unsigned long data, void *arg)
790{
791 int ret;
792
793 cds_ssr_protect(__func__);
794 ret = __wlan_hdd_ipv4_changed(nb, data, arg);
795 cds_ssr_unprotect(__func__);
796
797 return ret;
798}
799
800/**
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530801 * hdd_get_ipv4_local_interface() - get ipv4 local interafce from iface list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800802 * @pAdapter: Adapter context for which ARP offload is to be configured
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800803 *
804 * Return:
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530805 * ifa - on successful operation,
806 * NULL - on failure of operation
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800807 */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530808static struct in_ifaddr *hdd_get_ipv4_local_interface(
809 hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800810{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530811 struct in_ifaddr **ifap = NULL;
812 struct in_ifaddr *ifa = NULL;
813 struct in_device *in_dev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800814
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530815 in_dev = __in_dev_get_rtnl(pAdapter->dev);
816 if (in_dev) {
817 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
818 ifap = &ifa->ifa_next) {
819 if (!strcmp(pAdapter->dev->name, ifa->ifa_label)) {
820 /* if match break */
821 return ifa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800822 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800823 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530824 }
825 ifa = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800826
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530827 return ifa;
828}
829
830void hdd_enable_arp_offload(hdd_adapter_t *adapter,
831 enum pmo_offload_trigger trigger)
832{
833 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
834 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
835 QDF_STATUS status;
836 struct pmo_arp_req *arp_req = NULL;
837 struct in_ifaddr *ifa = NULL;
838
839 ENTER();
840 arp_req = qdf_mem_malloc(sizeof(*arp_req));
841 if (!arp_req) {
842 hdd_err("cannot allocate arp_req");
843 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800844 }
Jeff Johnson68755312017-02-10 11:46:55 -0800845
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530846 arp_req->psoc = psoc;
847 arp_req->vdev_id = adapter->sessionId;
848 arp_req->trigger = trigger;
Jeff Johnson68755312017-02-10 11:46:55 -0800849
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530850 ifa = hdd_get_ipv4_local_interface(adapter);
851 if (ifa && ifa->ifa_local) {
852 arp_req->ipv4_addr = (uint32_t)ifa->ifa_local;
853 status = pmo_ucfg_cache_arp_offload_req(arp_req);
854 if (status == QDF_STATUS_SUCCESS) {
855 status = pmo_ucfg_enable_arp_offload_in_fwr(
856 adapter->hdd_vdev, trigger);
857 if (status == QDF_STATUS_SUCCESS)
858 hdd_wlan_offload_event(
859 PMO_IPV4_ARP_REPLY_OFFLOAD,
860 PMO_OFFLOAD_ENABLE);
861 else
862 hdd_info("fail to enable arp offload in fwr");
863 } else
864 hdd_info("fail to cache arp offload request");
865 } else {
866 hdd_notice("IP Address is not assigned");
867 status = QDF_STATUS_NOT_INITIALIZED;
868 }
869out:
870 if (arp_req)
871 qdf_mem_free(arp_req);
872 EXIT();
873
874}
875
876void hdd_disable_arp_offload(hdd_adapter_t *adapter,
877 enum pmo_offload_trigger trigger)
878{
879 QDF_STATUS status;
880
881 ENTER();
882 status = pmo_ucfg_flush_arp_offload_req(adapter->hdd_vdev);
883 if (status != QDF_STATUS_SUCCESS) {
884 hdd_err("Failed to flush arp Offload");
885 goto out;
Jeff Johnson68755312017-02-10 11:46:55 -0800886 }
887
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530888 status = pmo_ucfg_disable_arp_offload_in_fwr(adapter->hdd_vdev, trigger);
889 if (status == QDF_STATUS_SUCCESS)
890 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD,
891 PMO_OFFLOAD_DISABLE);
892 else
893 hdd_info("fail to disable arp offload");
894out:
895 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800896}
897
Ravi Kumar Bokka794fd712017-03-21 20:52:46 +0530898void hdd_enable_non_arp_hw_broadcast_filter(hdd_adapter_t *adapter)
899{
900 QDF_STATUS status;
901
902 ENTER();
903
904 status = pmo_ucfg_enable_non_arp_bcast_filter_in_fwr(
905 adapter->hdd_vdev);
906
907 if (status != QDF_STATUS_SUCCESS)
908 hdd_info("Failed to enable broadcast filter");
909
910 EXIT();
911}
912
913void hdd_disable_non_arp_hw_broadcast_filter(hdd_adapter_t *adapter)
914{
915 QDF_STATUS status;
916
917 ENTER();
918
919 status = pmo_ucfg_disable_non_arp_bcast_filter_in_fwr(
920 adapter->hdd_vdev);
921 if (status != QDF_STATUS_SUCCESS)
922 hdd_info("Failed to disable broadcast filter");
923
924 EXIT();
925}
926
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530927void hdd_enable_mc_addr_filtering(hdd_adapter_t *adapter,
928 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929{
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530930 hdd_context_t *hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
931 QDF_STATUS status;
932 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800933
Ravi Joshi24477b72016-07-19 15:45:09 -0700934 ENTER();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530935 if (wlan_hdd_validate_context(hdd_ctx))
936 goto out;
Ravi Joshi24477b72016-07-19 15:45:09 -0700937
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530938 status = pmo_ucfg_enable_mc_addr_filtering_in_fwr(psoc,
939 adapter->sessionId, trigger);
940 if (status != QDF_STATUS_SUCCESS)
941 hdd_info("failed to enable mc list status %d", status);
942out:
Ravi Joshi24477b72016-07-19 15:45:09 -0700943 EXIT();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530944
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800945}
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530946
947void hdd_disable_mc_addr_filtering(hdd_adapter_t *adapter,
948 enum pmo_offload_trigger trigger)
949{
950 hdd_context_t *hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
951 QDF_STATUS status = QDF_STATUS_SUCCESS;
952 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
953
954 ENTER();
955 if (wlan_hdd_validate_context(hdd_ctx))
956 goto out;
957
958 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
959 adapter->sessionId, trigger);
960 if (status != QDF_STATUS_SUCCESS)
961 hdd_info("failed to disable mc list status %d", status);
962out:
963 EXIT();
964
965}
966
967int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config)
968{
969 QDF_STATUS status;
970 int ret = 0;
971
972 ENTER();
973 /* cache mc addr list */
974 status = pmo_ucfg_cache_mc_addr_list(mc_list_config);
975 if (status != QDF_STATUS_SUCCESS) {
976 hdd_info("fail to cache mc list status %d", status);
977 ret = -EINVAL;
978 }
979 EXIT();
980
981 return ret;
982}
983
984void hdd_disable_and_flush_mc_addr_list(hdd_adapter_t *adapter,
985 enum pmo_offload_trigger trigger)
986{
987 hdd_context_t *hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
988 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
989 QDF_STATUS status = QDF_STATUS_SUCCESS;
990
991 ENTER();
992 /* disable mc list first */
993 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
994 adapter->sessionId, trigger);
995 if (status != QDF_STATUS_SUCCESS)
996 hdd_info("fail to disable mc list");
997
998 /* flush mc list */
999 status = pmo_ucfg_flush_mc_addr_list(psoc, adapter->sessionId);
1000 if (status != QDF_STATUS_SUCCESS)
1001 hdd_info("fail to flush mc list status %d", status);
1002 EXIT();
1003
1004 return;
1005
1006}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001007
1008/**
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001009 * hdd_update_conn_state_mask(): record info needed by wma_suspend_req
1010 * @adapter: adapter to get info from
1011 * @conn_state_mask: mask of connection info
1012 *
1013 * currently only need to send connection info.
1014 */
1015static void
1016hdd_update_conn_state_mask(hdd_adapter_t *adapter, uint32_t *conn_state_mask)
1017{
1018
1019 eConnectionState connState;
1020 hdd_station_ctx_t *sta_ctx;
1021 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1022 connState = sta_ctx->conn_info.connState;
1023
1024 if (connState == eConnectionState_Associated ||
1025 connState == eConnectionState_IbssConnected)
1026 *conn_state_mask |= (1 << adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027}
1028
1029/**
1030 * hdd_suspend_wlan() - Driver suspend function
1031 * @callback: Callback function to invoke when driver is ready to suspend
1032 * @callbackContext: Context to pass back to @callback function
1033 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301034 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001035 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301036static int
1037hdd_suspend_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001038{
1039 hdd_context_t *pHddCtx;
1040
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301041 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001042 hdd_adapter_t *pAdapter = NULL;
1043 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001044 uint32_t conn_state_mask = 0;
Jeff Johnsonc3273322016-07-06 15:28:17 -07001045 hdd_info("WLAN being suspended by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046
Anurag Chouhan6d760662016-02-20 16:05:43 +05301047 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001048 if (!pHddCtx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001049 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301050 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001051 }
1052
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001053 if (cds_is_driver_recovering()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001054 hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001055 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301056 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001057 }
1058
1059 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301060 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001061 pAdapter = pAdapterNode->pAdapter;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301062 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1063 hdd_err("invalid session id: %d", pAdapter->sessionId);
1064 goto next_adapter;
1065 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001066
1067 /* stop all TX queues before suspend */
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001068 hdd_debug("Disabling queues");
Himanshu Agarwal865201d2017-04-12 15:45:31 +05301069 wlan_hdd_netif_queue_control(pAdapter,
1070 WLAN_STOP_ALL_NETIF_QUEUE,
1071 WLAN_CONTROL_PATH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001072
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001073 /* Configure supported OffLoads */
Mukul Sharma3ba26b82017-01-12 21:59:41 +05301074 hdd_enable_host_offloads(pAdapter, pmo_apps_suspend);
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001075 hdd_update_conn_state_mask(pAdapter, &conn_state_mask);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301076next_adapter:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001077 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1078 pAdapterNode = pNext;
1079 }
1080
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301081 status = pmo_ucfg_psoc_user_space_suspend_req(pHddCtx->hdd_psoc,
1082 QDF_SYSTEM_SUSPEND);
1083 if (status != QDF_STATUS_SUCCESS)
1084 return -EAGAIN;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001085
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001086 pHddCtx->hdd_wlan_suspended = true;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301087 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001088
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301089 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001090}
1091
1092/**
1093 * hdd_resume_wlan() - Driver resume function
1094 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301095 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001096 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301097static int hdd_resume_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098{
1099 hdd_context_t *pHddCtx;
1100 hdd_adapter_t *pAdapter = NULL;
1101 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301102 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001103
Dustin Brown2d228232016-09-22 15:06:19 -07001104 hdd_info("WLAN being resumed by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105
Anurag Chouhan6d760662016-02-20 16:05:43 +05301106 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001107 if (!pHddCtx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001108 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301109 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001110 }
1111
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001112 if (cds_is_driver_recovering()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001113 hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001114 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301115 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001116 }
1117
1118 pHddCtx->hdd_wlan_suspended = false;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301119 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001120
1121 /*loop through all adapters. Concurrency */
1122 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
1123
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301124 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001125 pAdapter = pAdapterNode->pAdapter;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301126 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1127 hdd_err("invalid session id: %d", pAdapter->sessionId);
1128 goto next_adapter;
1129 }
1130 /* Disable supported OffLoads */
1131 hdd_disable_host_offloads(pAdapter, pmo_apps_resume);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001132
1133 /* wake the tx queues */
Dustin Brown2d228232016-09-22 15:06:19 -07001134 hdd_info("Enabling queues");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001135 wlan_hdd_netif_queue_control(pAdapter,
1136 WLAN_WAKE_ALL_NETIF_QUEUE,
1137 WLAN_CONTROL_PATH);
1138
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301139next_adapter:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001140 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1141 pAdapterNode = pNext;
1142 }
1143 hdd_ipa_resume(pHddCtx);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301144 status = pmo_ucfg_psoc_user_space_resume_req(pHddCtx->hdd_psoc,
1145 QDF_SYSTEM_SUSPEND);
1146 if (status != QDF_STATUS_SUCCESS)
1147 return -EAGAIN;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001148
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301149 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001150}
1151
1152/**
1153 * DOC: SSR Timer
1154 *
1155 * When SSR is initiated, an SSR timer is started. Under normal
1156 * circumstances SSR should complete amd the timer should be deleted
1157 * before it fires. If the SSR timer does fire, it indicates SSR has
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301158 * taken too long, and our only recourse is to invoke the QDF_BUG()
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001159 * API which can allow a crashdump to be captured.
1160 */
1161
1162/**
1163 * hdd_ssr_timer_init() - Initialize SSR Timer
1164 *
1165 * Return: None.
1166 */
1167static void hdd_ssr_timer_init(void)
1168{
1169 init_timer(&ssr_timer);
1170}
1171
1172/**
1173 * hdd_ssr_timer_del() - Delete SSR Timer
1174 *
1175 * Return: None.
1176 */
1177static void hdd_ssr_timer_del(void)
1178{
1179 del_timer(&ssr_timer);
1180 ssr_timer_started = false;
1181}
1182
1183/**
1184 * hdd_ssr_timer_cb() - SSR Timer callback function
1185 * @data: opaque data registered with timer infrastructure
1186 *
1187 * Return: None.
1188 */
1189static void hdd_ssr_timer_cb(unsigned long data)
1190{
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001191 hdd_info("HDD SSR timer expired!");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301192 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001193}
1194
1195/**
1196 * hdd_ssr_timer_start() - Start SSR Timer
1197 * @msec: Timer timeout value in milliseconds
1198 *
1199 * Return: None.
1200 */
1201static void hdd_ssr_timer_start(int msec)
1202{
1203 if (ssr_timer_started) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001204 hdd_debug("Trying to start SSR timer when " "it's running!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001205 }
1206 ssr_timer.expires = jiffies + msecs_to_jiffies(msec);
1207 ssr_timer.function = hdd_ssr_timer_cb;
1208 add_timer(&ssr_timer);
1209 ssr_timer_started = true;
1210}
1211
1212/**
Komal Seelam78ff65a2016-08-18 15:25:24 +05301213 * hdd_svc_fw_shutdown_ind() - API to send FW SHUTDOWN IND to Userspace
1214 *
1215 * @dev: Device Pointer
1216 *
1217 * Return: None
1218 */
1219void hdd_svc_fw_shutdown_ind(struct device *dev)
1220{
1221 hdd_context_t *hdd_ctx;
1222 v_CONTEXT_t g_context;
1223
1224 g_context = cds_get_global_context();
1225
1226 if (!g_context)
1227 return;
1228
1229 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1230
1231 hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
1232 WLAN_SVC_FW_SHUTDOWN_IND,
1233 NULL, 0) : 0;
1234}
1235
1236/**
Arun Khandavallicc544b32017-01-30 19:52:16 +05301237 * hdd_ssr_restart_sap() - restart sap on SSR
1238 * @hdd_ctx: hdd context
1239 *
1240 * Return: nothing
1241 */
1242static void hdd_ssr_restart_sap(hdd_context_t *hdd_ctx)
1243{
1244 QDF_STATUS status;
1245 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
1246 hdd_adapter_t *adapter;
1247
1248 ENTER();
1249
1250 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
1251 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
1252 adapter = adapter_node->pAdapter;
1253 if (adapter && adapter->device_mode == QDF_SAP_MODE) {
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001254 if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001255 hdd_debug("Restart prev SAP session");
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001256 wlan_hdd_start_sap(adapter, true);
1257 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05301258 }
1259 status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next);
1260 adapter_node = next;
1261 }
1262
1263 EXIT();
1264}
1265
1266/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001267 * hdd_wlan_shutdown() - HDD SSR shutdown function
1268 *
1269 * This function is called by the HIF to shutdown the driver during SSR.
1270 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301271 * Return: QDF_STATUS_SUCCESS if the driver was shut down,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001272 * or an error status otherwise
1273 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301274QDF_STATUS hdd_wlan_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001275{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001276 v_CONTEXT_t p_cds_context = NULL;
1277 hdd_context_t *pHddCtx;
1278 p_cds_sched_context cds_sched_context = NULL;
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001279 QDF_STATUS qdf_status;
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001280 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001281
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001282 hdd_info("WLAN driver shutting down!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001283
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001284 /* If SSR never completes, then do kernel panic. */
1285 hdd_ssr_timer_init();
1286 hdd_ssr_timer_start(HDD_SSR_BRING_UP_TIME);
1287
1288 /* Get the global CDS context. */
1289 p_cds_context = cds_get_global_context();
1290 if (!p_cds_context) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001291 hdd_err("Global CDS context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301292 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001293 }
1294
1295 /* Get the HDD context. */
Anurag Chouhan6d760662016-02-20 16:05:43 +05301296 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001297 if (!pHddCtx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001298 hdd_err("HDD context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301299 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001300 }
1301
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -08001302 policy_mgr_clear_concurrent_session_count(pHddCtx->hdd_psoc);
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301303
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001304 hdd_debug("Invoking packetdump deregistration API");
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301305 wlan_deregister_txrx_packetdump();
Sandeep Puligilla8de3c1c2017-04-13 17:56:18 -07001306 wlan_cfg80211_cleanup_scan_queue(pHddCtx->hdd_pdev);
Govind Singh9c58eba2016-09-02 16:23:06 +05301307 hdd_ipa_uc_ssr_deinit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001308 hdd_reset_all_adapters(pHddCtx);
1309
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301310 /* Flush cached rx frame queue */
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001311 if (soc)
1312 cdp_flush_cache_rx_queue(soc);
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301313
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301314 /* De-register the HDD callbacks */
1315 hdd_deregister_cb(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001316
1317 cds_sched_context = get_cds_sched_ctxt();
1318
Rajeev Kumareada0d02016-12-08 17:44:17 -08001319 if (pHddCtx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001320 scheduler_resume();
Rajeev Kumareada0d02016-12-08 17:44:17 -08001321 pHddCtx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001322 }
1323#ifdef QCA_CONFIG_SMP
1324 if (true == pHddCtx->is_ol_rx_thread_suspended) {
1325 complete(&cds_sched_context->ol_resume_rx_event);
1326 pHddCtx->is_ol_rx_thread_suspended = false;
1327 }
1328#endif
1329
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001330 qdf_status = cds_sched_close(p_cds_context);
1331 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1332 hdd_err("Failed to close CDS Scheduler");
1333 QDF_ASSERT(false);
1334 }
1335
Nitesh Shah61c10d92016-10-19 19:29:15 +05301336 qdf_mc_timer_stop(&pHddCtx->tdls_source_timer);
1337
Prashanth Bhattaab004382016-10-11 16:08:11 -07001338 hdd_bus_bandwidth_destroy(pHddCtx);
1339
Rajeev Kumar3fef4e82017-03-31 20:25:23 -07001340 hdd_wlan_stop_modules(pHddCtx, false);
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301341
Jeff Johnsonf7f66f02016-09-23 14:50:11 -07001342 hdd_lpass_notify_stop(pHddCtx);
Yuanyuan Liu3e918e52016-08-17 15:41:35 -07001343
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001344 hdd_info("WLAN driver shutdown complete");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301345 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001346}
1347
Sen, Devendra154b3c42017-02-13 20:44:15 +05301348#ifdef FEATURE_WLAN_DIAG_SUPPORT
1349/**
1350* hdd_wlan_ssr_reinit_event()- send ssr reinit state
1351*
1352* This Function send send ssr reinit state diag event
1353*
1354* Return: void.
1355*/
1356static void hdd_wlan_ssr_reinit_event(void)
1357{
1358 WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit);
1359 qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit));
1360 ssr_reinit.status = SSR_SUB_SYSTEM_REINIT;
1361 WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit,
1362 EVENT_WLAN_SSR_REINIT_SUBSYSTEM);
1363}
1364#else
1365static inline void hdd_wlan_ssr_reinit_event(void)
1366{
1367
1368}
1369#endif
1370
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001371/**
1372 * hdd_wlan_re_init() - HDD SSR re-init function
1373 *
1374 * This function is called by the HIF to re-initialize the driver after SSR.
1375 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301376 * Return: QDF_STATUS_SUCCESS if the driver was re-initialized,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001377 * or an error status otherwise
1378 */
Arun Khandavallifae92942016-08-01 13:31:08 +05301379QDF_STATUS hdd_wlan_re_init(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001380{
Arun Khandavallifae92942016-08-01 13:31:08 +05301381
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001382 v_CONTEXT_t p_cds_context = NULL;
1383 hdd_context_t *pHddCtx = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001384 hdd_adapter_t *pAdapter;
Arun Khandavallifae92942016-08-01 13:31:08 +05301385 int ret;
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301386 bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001387
1388 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1389
1390 /* Get the CDS context */
1391 p_cds_context = cds_get_global_context();
1392 if (p_cds_context == NULL) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001393 hdd_err("Failed cds_get_global_context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001394 goto err_re_init;
1395 }
1396
1397 /* Get the HDD context */
Anurag Chouhan6d760662016-02-20 16:05:43 +05301398 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001399 if (!pHddCtx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001400 hdd_err("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001401 goto err_re_init;
1402 }
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301403 bug_on_reinit_failure = pHddCtx->config->bug_on_reinit_failure;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001404
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001405 /* The driver should always be initialized in STA mode after SSR */
1406 hdd_set_conparam(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001407 /* Try to get an adapter from mode ID */
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001408 pAdapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001409 if (!pAdapter) {
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001410 pAdapter = hdd_get_adapter(pHddCtx, QDF_SAP_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411 if (!pAdapter) {
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001412 pAdapter = hdd_get_adapter(pHddCtx, QDF_IBSS_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001413 if (!pAdapter) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001414 hdd_err("Failed to get Adapter!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001415 }
1416 }
1417 }
1418
Nirav Shahcc1f1ae2016-04-26 11:41:29 +05301419 if (pHddCtx->config->enable_dp_trace)
1420 qdf_dp_trace_init();
1421
Prashanth Bhattaab004382016-10-11 16:08:11 -07001422 hdd_bus_bandwidth_init(pHddCtx);
1423
Arun Khandavallicc544b32017-01-30 19:52:16 +05301424
Arun Khandavallifae92942016-08-01 13:31:08 +05301425 ret = hdd_wlan_start_modules(pHddCtx, pAdapter, true);
1426 if (ret) {
1427 hdd_err("Failed to start wlan after error");
1428 goto err_wiphy_unregister;
1429 }
1430
Arun Khandavallia96c2c02016-05-17 19:15:34 +05301431 hdd_wlan_get_version(pHddCtx, NULL, NULL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001432
Wu Gao36717432016-11-21 15:09:48 +08001433 wlan_hdd_send_svc_nlink_msg(pHddCtx->radio_index,
1434 WLAN_SVC_FW_CRASHED_IND, NULL, 0);
1435
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001436 /* Restart all adapters */
1437 hdd_start_all_adapters(pHddCtx);
1438
Sreelakshmi Konamkib53c6292017-03-01 13:13:23 +05301439 pHddCtx->last_scan_reject_session_id = 0xFF;
1440 pHddCtx->last_scan_reject_reason = 0;
1441 pHddCtx->last_scan_reject_timestamp = 0;
1442
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001443 pHddCtx->btCoexModeSet = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001444
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001445 /* Allow the phone to go to sleep */
1446 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1447
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301448 ret = hdd_register_cb(pHddCtx);
1449 if (ret) {
1450 hdd_err("Failed to register HDD callbacks!");
Chandrasekaran Manishekarcde33d72016-04-14 19:03:39 +05301451 goto err_cds_disable;
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301452 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453
Jeff Johnson9afc5012016-09-23 13:56:27 -07001454 hdd_lpass_notify_start(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001455
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001456 hdd_info("WLAN host driver reinitiation completed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001457 goto success;
1458
1459err_cds_disable:
Rajeev Kumar3fef4e82017-03-31 20:25:23 -07001460 hdd_wlan_stop_modules(pHddCtx, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001461
Arun Khandavallifae92942016-08-01 13:31:08 +05301462err_wiphy_unregister:
Ashish Kumar Dhanotiyaaa2b17c2017-03-29 00:41:32 +05301463 if (bug_on_reinit_failure)
1464 QDF_BUG(0);
1465
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001466 if (pHddCtx) {
Ashish Kumar Dhanotiyaaa2b17c2017-03-29 00:41:32 +05301467 /* Unregister the Notifier's */
1468 hdd_unregister_notifiers(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001469 ptt_sock_deactivate_svc();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001470 nl_srv_exit();
1471
Ashish Kumar Dhanotiyaaa2b17c2017-03-29 00:41:32 +05301472 hdd_close_all_adapters(pHddCtx, false);
1473 wlan_hdd_cfg80211_deinit(pHddCtx->wiphy);
1474 hdd_lpass_notify_stop(pHddCtx);
Nirav Shahed34b212016-04-25 10:59:16 +05301475 wlan_hdd_deinit_tx_rx_histogram(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001476 wiphy_unregister(pHddCtx->wiphy);
Ashish Kumar Dhanotiyaaa2b17c2017-03-29 00:41:32 +05301477
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001478 }
1479
1480err_re_init:
Ashish Kumar Dhanotiyaaa2b17c2017-03-29 00:41:32 +05301481 hdd_ssr_timer_del();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001482 /* Allow the phone to go to sleep */
1483 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301484 if (bug_on_reinit_failure)
1485 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001486 return -EPERM;
1487
1488success:
Arun Khandavallicc544b32017-01-30 19:52:16 +05301489 if (pHddCtx->config->sap_internal_restart)
1490 hdd_ssr_restart_sap(pHddCtx);
Srinivas Girigowda02c084d2016-10-18 15:27:21 -07001491 hdd_ssr_timer_del();
Sen, Devendra154b3c42017-02-13 20:44:15 +05301492 hdd_wlan_ssr_reinit_event();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301493 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001494}
1495
1496/**
1497 * wlan_hdd_set_powersave() - Set powersave mode
1498 * @adapter: adapter upon which the request was received
Dustin Brownf660fb42016-09-09 12:04:00 -07001499 * @allow_power_save: is wlan allowed to go into power save mode
1500 * @timeout: timeout period in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001501 *
1502 * Return: 0 on success, non-zero on any error
1503 */
Dustin Brownf660fb42016-09-09 12:04:00 -07001504static int wlan_hdd_set_powersave(hdd_adapter_t *adapter,
1505 bool allow_power_save, uint32_t timeout)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001506{
1507 tHalHandle hal;
1508 hdd_context_t *hdd_ctx;
1509
1510 if (NULL == adapter) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001511 hdd_err("Adapter NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001512 return -ENODEV;
1513 }
1514
1515 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1516 if (!hdd_ctx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001517 hdd_err("hdd context is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001518 return -EINVAL;
1519 }
1520
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001521 hdd_debug("Allow power save: %d", allow_power_save);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001522 hal = WLAN_HDD_GET_HAL_CTX(adapter);
1523
Dustin Brownf660fb42016-09-09 12:04:00 -07001524 if (allow_power_save) {
1525 if (QDF_STA_MODE == adapter->device_mode ||
1526 QDF_P2P_CLIENT_MODE == adapter->device_mode) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001527 hdd_debug("Disabling Auto Power save timer");
Dustin Brownf660fb42016-09-09 12:04:00 -07001528 sme_ps_disable_auto_ps_timer(
1529 WLAN_HDD_GET_HAL_CTX(adapter),
1530 adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001531 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001532
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001533 if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001534 hdd_debug("Wlan driver Entering Power save");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001535
1536 /*
1537 * Enter Power Save command received from GUI
1538 * this means DHCP is completed
1539 */
1540 sme_ps_enable_disable(hal, adapter->sessionId,
1541 SME_PS_ENABLE);
1542 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001543 hdd_debug("Power Save is not enabled in the cfg");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001544 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001545 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001546 hdd_debug("Wlan driver Entering Full Power");
Dustin Brownf660fb42016-09-09 12:04:00 -07001547
1548 /*
1549 * Enter Full power command received from GUI
1550 * this means we are disconnected
1551 */
1552 sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1553 adapter->sessionId);
1554 sme_ps_enable_disable(hal, adapter->sessionId, SME_PS_DISABLE);
1555 sme_ps_enable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1556 adapter->sessionId, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001557 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001558
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001559 return 0;
1560}
1561
Dustin Brown105d7902016-10-03 16:27:59 -07001562static void wlan_hdd_print_suspend_fail_stats(hdd_context_t *hdd_ctx)
1563{
Dustin Brownd9322482017-01-09 12:46:03 -08001564 struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats;
Dustin Brown105d7902016-10-03 16:27:59 -07001565 hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d",
Dustin Brownd9322482017-01-09 12:46:03 -08001566 stats->suspend_fail[SUSPEND_FAIL_IPA],
1567 stats->suspend_fail[SUSPEND_FAIL_RADAR],
1568 stats->suspend_fail[SUSPEND_FAIL_ROAM],
1569 stats->suspend_fail[SUSPEND_FAIL_SCAN],
1570 stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]);
Dustin Brown105d7902016-10-03 16:27:59 -07001571}
1572
1573void wlan_hdd_inc_suspend_stats(hdd_context_t *hdd_ctx,
1574 enum suspend_fail_reason reason)
1575{
1576 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001577 hdd_ctx->suspend_resume_stats.suspend_fail[reason]++;
Dustin Brown105d7902016-10-03 16:27:59 -07001578 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
1579}
1580
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001581/**
1582 * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1583 * @wiphy: Pointer to wiphy
1584 *
1585 * This API is called when cfg80211 driver resumes driver updates
1586 * latest sched_scan scan result(if any) to cfg80211 database
1587 *
1588 * Return: integer status
1589 */
1590static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1591{
1592 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1593 hdd_adapter_t *pAdapter;
1594 hdd_adapter_list_node_t *pAdapterNode, *pNext;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301595 QDF_STATUS status = QDF_STATUS_SUCCESS;
Dustin Brownd9322482017-01-09 12:46:03 -08001596 int exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001597 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1598
1599 ENTER();
1600
Dustin Brownd9322482017-01-09 12:46:03 -08001601 if (cds_is_driver_recovering()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001602 hdd_debug("Driver is recovering; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001603 exit_code = 0;
1604 goto exit_with_code;
1605 }
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001606
Anurag Chouhan6d760662016-02-20 16:05:43 +05301607 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001608 hdd_err("Command not allowed in FTM mode");
Dustin Brownd9322482017-01-09 12:46:03 -08001609 exit_code = -EINVAL;
1610 goto exit_with_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001611 }
1612
Dustin Brownd9322482017-01-09 12:46:03 -08001613 exit_code = wlan_hdd_validate_context(pHddCtx);
1614 if (exit_code) {
1615 hdd_err("Invalid HDD context");
1616 goto exit_with_code;
1617 }
Arun Khandavallifae92942016-08-01 13:31:08 +05301618
1619 mutex_lock(&pHddCtx->iface_change_lock);
1620 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
1621 mutex_unlock(&pHddCtx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001622 hdd_debug("Driver is not enabled; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001623 exit_code = 0;
1624 goto exit_with_code;
Arun Khandavallifae92942016-08-01 13:31:08 +05301625 }
1626 mutex_unlock(&pHddCtx->iface_change_lock);
Dustin Brownd9322482017-01-09 12:46:03 -08001627
Yuanyuan Liu13738502016-04-06 17:41:37 -07001628 pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_MEDIUM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001629
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301630 status = hdd_resume_wlan();
1631 if (status != QDF_STATUS_SUCCESS) {
1632 exit_code = 0;
1633 goto exit_with_code;
1634 }
Rajeev Kumareada0d02016-12-08 17:44:17 -08001635 /* Resume control path scheduler */
1636 if (pHddCtx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001637 scheduler_resume();
Rajeev Kumareada0d02016-12-08 17:44:17 -08001638 pHddCtx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001639 }
1640#ifdef QCA_CONFIG_SMP
1641 /* Resume tlshim Rx thread */
1642 if (pHddCtx->is_ol_rx_thread_suspended) {
1643 complete(&cds_sched_context->ol_resume_rx_event);
1644 pHddCtx->is_ol_rx_thread_suspended = false;
1645 }
1646#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301648 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301649 TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
1650 NO_SESSION, pHddCtx->isWiphySuspended));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301651 qdf_spin_lock(&pHddCtx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001652 pHddCtx->isWiphySuspended = false;
1653 if (true != pHddCtx->isSchedScanUpdatePending) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301654 qdf_spin_unlock(&pHddCtx->sched_scan_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001655 hdd_debug("Return resume is not due to PNO indication");
Dustin Brownd9322482017-01-09 12:46:03 -08001656 goto exit_with_success;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001657 }
1658 /* Reset flag to avoid updatating cfg80211 data old results again */
1659 pHddCtx->isSchedScanUpdatePending = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301660 qdf_spin_unlock(&pHddCtx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001661
1662 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301663 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001664 pAdapter = pAdapterNode->pAdapter;
1665 if ((NULL != pAdapter) &&
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001666 (QDF_STA_MODE == pAdapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001667 if (0 !=
1668 wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy,
1669 pAdapter, 0)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001670 hdd_warn("NO SCAN result");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001671 } else {
1672 /* Acquire wakelock to handle the case where
1673 * APP's tries to suspend immediately after
1674 * updating the scan results. Whis results in
1675 * app's is in suspended state and not able to
1676 * process the connect request to AP
1677 */
Sreelakshmi Konamki22528532016-09-06 16:34:50 +05301678 hdd_prevent_suspend_timeout(
1679 HDD_WAKE_LOCK_RESUME_DURATION,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001680 WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN);
1681 cfg80211_sched_scan_results(pHddCtx->wiphy);
1682 }
1683
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001684 hdd_debug("cfg80211 scan result database updated");
Dustin Brownd9322482017-01-09 12:46:03 -08001685 goto exit_with_success;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001686 }
1687 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1688 pAdapterNode = pNext;
1689 }
1690
Dustin Brownd9322482017-01-09 12:46:03 -08001691exit_with_success:
1692 pHddCtx->suspend_resume_stats.resumes++;
1693 exit_code = 0;
1694
1695exit_with_code:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301696 EXIT();
Dustin Brownd9322482017-01-09 12:46:03 -08001697 return exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698}
1699
1700/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001701 * wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1702 * @wiphy: Pointer to wiphy
1703 *
1704 * This API is called when cfg80211 driver resumes driver updates
1705 * latest sched_scan scan result(if any) to cfg80211 database
1706 *
1707 * Return: integer status
1708 */
1709int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1710{
1711 int ret;
1712
1713 cds_ssr_protect(__func__);
1714 ret = __wlan_hdd_cfg80211_resume_wlan(wiphy);
1715 cds_ssr_unprotect(__func__);
1716
1717 return ret;
1718}
1719
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001720static void hdd_suspend_cb(void)
1721{
1722 hdd_context_t *hdd_ctx;
1723
1724 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1725 if (!hdd_ctx) {
1726 cds_err("HDD context is NULL");
1727 return;
1728 }
1729
1730 complete(&hdd_ctx->mc_sus_event_var);
1731}
1732
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001733/**
1734 * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1735 * @wiphy: Pointer to wiphy
1736 * @wow: Pointer to wow
1737 *
1738 * This API is called when cfg80211 driver suspends
1739 *
1740 * Return: integer status
1741 */
1742static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1743 struct cfg80211_wowlan *wow)
1744{
1745#ifdef QCA_CONFIG_SMP
1746#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */
1747#endif
1748 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1749 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1750 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
1751 hdd_adapter_t *pAdapter;
1752 hdd_scaninfo_t *pScanInfo;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301753 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001754 int rc;
1755
1756 ENTER();
1757
Anurag Chouhan6d760662016-02-20 16:05:43 +05301758 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001759 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001760 return -EINVAL;
1761 }
1762
1763 rc = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301764 if (0 != rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001765 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001766
Arun Khandavallifae92942016-08-01 13:31:08 +05301767 mutex_lock(&pHddCtx->iface_change_lock);
1768 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
1769 mutex_unlock(&pHddCtx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001770 hdd_debug("Driver Modules not Enabled ");
Arun Khandavallifae92942016-08-01 13:31:08 +05301771 return 0;
1772 }
1773 mutex_unlock(&pHddCtx->iface_change_lock);
1774
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775 /* If RADAR detection is in progress (HDD), prevent suspend. The flag
1776 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true
1777 * until CAC is done for a SoftAP which is in started state.
1778 */
1779 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301780 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001781 pAdapter = pAdapterNode->pAdapter;
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301782
1783 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1784 hdd_err("invalid session id: %d", pAdapter->sessionId);
1785 goto next_adapter;
1786 }
1787
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001788 if (QDF_SAP_MODE == pAdapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789 if (BSS_START ==
1790 WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter)->bssState &&
1791 true ==
1792 WLAN_HDD_GET_AP_CTX_PTR(pAdapter)->
1793 dfs_cac_block_tx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001794 hdd_err("RADAR detection in progress, do not allow suspend");
Dustin Brown105d7902016-10-03 16:27:59 -07001795 wlan_hdd_inc_suspend_stats(pHddCtx,
1796 SUSPEND_FAIL_RADAR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001797 return -EAGAIN;
1798 } else if (!pHddCtx->config->enableSapSuspend) {
1799 /* return -EOPNOTSUPP if SAP does not support
1800 * suspend
1801 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001802 hdd_err("SAP does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001803 return -EOPNOTSUPP;
1804 }
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001805 } else if (QDF_P2P_GO_MODE == pAdapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001806 if (!pHddCtx->config->enableSapSuspend) {
1807 /* return -EOPNOTSUPP if GO does not support
1808 * suspend
1809 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001810 hdd_err("GO does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001811 return -EOPNOTSUPP;
1812 }
1813 }
Masti, Narayanraddi3e26de62016-08-19 14:33:22 +05301814 if (pAdapter->is_roc_inprogress)
1815 wlan_hdd_cleanup_remain_on_channel_ctx(pAdapter);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301816next_adapter:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001817 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1818 pAdapterNode = pNext;
1819 }
1820
1821 /* Stop ongoing scan on each interface */
1822 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301823 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001824 pAdapter = pAdapterNode->pAdapter;
1825 pScanInfo = &pAdapter->scan_info;
1826
Sandeep Puligillaf8527122016-11-16 18:35:16 -08001827 if (sme_neighbor_middle_of_roaming
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001828 (pHddCtx->hHal, pAdapter->sessionId)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001829 hdd_err("Roaming in progress, do not allow suspend");
Dustin Brown105d7902016-10-03 16:27:59 -07001830 wlan_hdd_inc_suspend_stats(pHddCtx,
1831 SUSPEND_FAIL_ROAM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001832 return -EAGAIN;
1833 }
1834
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835 if (pScanInfo->mScanPending) {
1836 INIT_COMPLETION(pScanInfo->abortscan_event_var);
1837 hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId,
yeshwanth sriram guntuka310b3ac2016-11-15 23:25:26 +05301838 INVALID_SCAN_ID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839 eCSR_SCAN_ABORT_DEFAULT);
1840
1841 status =
1842 wait_for_completion_timeout(&pScanInfo->
1843 abortscan_event_var,
1844 msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN));
1845 if (!status) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001846 hdd_err("Timeout occurred while waiting for abort scan");
Dustin Brown105d7902016-10-03 16:27:59 -07001847 wlan_hdd_inc_suspend_stats(pHddCtx,
1848 SUSPEND_FAIL_SCAN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001849 return -ETIME;
1850 }
1851 }
1852 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1853 pAdapterNode = pNext;
1854 }
1855
1856 /*
1857 * Suspend IPA early before proceeding to suspend other entities like
1858 * firmware to avoid any race conditions.
1859 */
1860 if (hdd_ipa_suspend(pHddCtx)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001861 hdd_err("IPA not ready to suspend!");
Dustin Brown105d7902016-10-03 16:27:59 -07001862 wlan_hdd_inc_suspend_stats(pHddCtx, SUSPEND_FAIL_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001863 return -EAGAIN;
1864 }
1865
Rajeev Kumareada0d02016-12-08 17:44:17 -08001866 /* Suspend control path scheduler */
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001867 scheduler_register_hdd_suspend_callback(hdd_suspend_cb);
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301868 scheduler_set_event_mask(MC_SUSPEND_EVENT);
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001869 scheduler_wake_up_controller_thread();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001870
Rajeev Kumareada0d02016-12-08 17:44:17 -08001871 /* Wait for suspend confirmation from scheduler */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001872 rc = wait_for_completion_timeout(&pHddCtx->mc_sus_event_var,
1873 msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
1874 if (!rc) {
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301875 scheduler_clear_event_mask(MC_SUSPEND_EVENT);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001876 hdd_err("Failed to stop mc thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877 goto resume_tx;
1878 }
Rajeev Kumareada0d02016-12-08 17:44:17 -08001879 pHddCtx->is_scheduler_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001880
1881#ifdef QCA_CONFIG_SMP
1882 /* Suspend tlshim rx thread */
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301883 set_bit(RX_SUSPEND_EVENT, &cds_sched_context->ol_rx_event_flag);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001884 wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue);
1885 rc = wait_for_completion_timeout(&cds_sched_context->
1886 ol_suspend_rx_event,
1887 msecs_to_jiffies
1888 (RX_TLSHIM_SUSPEND_TIMEOUT));
1889 if (!rc) {
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301890 clear_bit(RX_SUSPEND_EVENT,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891 &cds_sched_context->ol_rx_event_flag);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001892 hdd_err("Failed to stop tl_shim rx thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001893 goto resume_all;
1894 }
1895 pHddCtx->is_ol_rx_thread_suspended = true;
1896#endif
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301897 if (hdd_suspend_wlan() < 0)
1898 goto resume_all;
1899
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301900 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301901 TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
1902 NO_SESSION, pHddCtx->isWiphySuspended));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001903 pHddCtx->isWiphySuspended = true;
1904
Yuanyuan Liu13738502016-04-06 17:41:37 -07001905 pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_NONE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001906
1907 EXIT();
1908 return 0;
1909
1910#ifdef QCA_CONFIG_SMP
1911resume_all:
1912
Rajeev Kumar0b732952016-12-08 17:51:39 -08001913 scheduler_resume();
Rajeev Kumareada0d02016-12-08 17:44:17 -08001914 pHddCtx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001915#endif
1916
1917resume_tx:
1918
1919 hdd_resume_wlan();
1920 return -ETIME;
1921
1922}
1923
1924/**
1925 * wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1926 * @wiphy: Pointer to wiphy
1927 * @wow: Pointer to wow
1928 *
1929 * This API is called when cfg80211 driver suspends
1930 *
1931 * Return: integer status
1932 */
1933int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1934 struct cfg80211_wowlan *wow)
1935{
1936 int ret;
1937
1938 cds_ssr_protect(__func__);
1939 ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
1940 cds_ssr_unprotect(__func__);
1941
1942 return ret;
1943}
1944
1945/**
Komal Seelama89be8d2016-09-29 11:09:26 +05301946 * hdd_stop_dhcp_ind() - API to stop DHCP sequence
1947 * @adapter: Adapter on which DHCP needs to be stopped
1948 *
1949 * Release the wakelock held for DHCP process and allow
1950 * the runtime pm to continue
1951 *
1952 * Return: None
1953 */
1954static void hdd_stop_dhcp_ind(hdd_adapter_t *adapter)
1955{
1956 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1957
Srinivas Girigowdac06543c2017-03-09 15:10:03 -08001958 hdd_debug("DHCP stop indicated through power save");
Komal Seelama89be8d2016-09-29 11:09:26 +05301959 sme_dhcp_stop_ind(hdd_ctx->hHal, adapter->device_mode,
1960 adapter->macAddressCurrent.bytes,
1961 adapter->sessionId);
1962 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
1963 qdf_runtime_pm_allow_suspend(adapter->connect_rpm_ctx.connect);
1964}
1965
1966/**
1967 * hdd_start_dhcp_ind() - API to start DHCP sequence
1968 * @adapter: Adapter on which DHCP needs to be stopped
1969 *
1970 * Prevent APPS suspend and the runtime suspend during
1971 * DHCP sequence
1972 *
1973 * Return: None
1974 */
1975static void hdd_start_dhcp_ind(hdd_adapter_t *adapter)
1976{
1977 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1978
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001979 hdd_debug("DHCP start indicated through power save");
Komal Seelama89be8d2016-09-29 11:09:26 +05301980 qdf_runtime_pm_prevent_suspend(adapter->connect_rpm_ctx.connect);
1981 hdd_prevent_suspend_timeout(1000, WIFI_POWER_EVENT_WAKELOCK_DHCP);
1982 sme_dhcp_start_ind(hdd_ctx->hHal, adapter->device_mode,
1983 adapter->macAddressCurrent.bytes,
1984 adapter->sessionId);
1985}
1986
1987/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001988 * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
1989 * @wiphy: Pointer to wiphy
1990 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07001991 * @allow_power_save: is wlan allowed to go into power save mode
1992 * @timeout: Timeout value in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001993 *
1994 * Return: 0 for success, non-zero for failure
1995 */
1996static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07001997 struct net_device *dev,
1998 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001999 int timeout)
2000{
2001 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2002 hdd_context_t *pHddCtx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002003 int status;
2004
Dustin Brownecfce632016-09-13 10:41:45 -07002005 ENTER();
2006
Dustin Brownf660fb42016-09-09 12:04:00 -07002007 if (timeout < 0) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002008 hdd_debug("User space timeout: %d; Using default instead: %d",
Dustin Brownf660fb42016-09-09 12:04:00 -07002009 timeout, AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE);
2010 timeout = AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE;
2011 }
2012
Anurag Chouhan6d760662016-02-20 16:05:43 +05302013 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002014 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015 return -EINVAL;
2016 }
2017
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302018 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
2019 hdd_err("invalid session id: %d", pAdapter->sessionId);
2020 return -EINVAL;
2021 }
2022
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302023 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002024 TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
2025 pAdapter->sessionId, timeout));
2026
2027 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2028 status = wlan_hdd_validate_context(pHddCtx);
2029
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302030 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002032
Arun Khandavalli99286452016-08-22 12:13:41 +05302033 mutex_lock(&pHddCtx->iface_change_lock);
2034 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
2035 mutex_unlock(&pHddCtx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002036 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05302037 return 0;
2038 }
2039 mutex_unlock(&pHddCtx->iface_change_lock);
2040
Dustin Brownf660fb42016-09-09 12:04:00 -07002041 status = wlan_hdd_set_powersave(pAdapter, allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042
Komal Seelama89be8d2016-09-29 11:09:26 +05302043 allow_power_save ? hdd_stop_dhcp_ind(pAdapter) :
2044 hdd_start_dhcp_ind(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002045
2046 EXIT();
2047 return status;
2048}
2049
2050/**
2051 * wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
2052 * @wiphy: Pointer to wiphy
2053 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07002054 * @allow_power_save: is wlan allowed to go into power save mode
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 * @timeout: Timeout value
2056 *
2057 * Return: 0 for success, non-zero for failure
2058 */
2059int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07002060 struct net_device *dev,
2061 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002062 int timeout)
2063{
2064 int ret;
2065
2066 cds_ssr_protect(__func__);
Dustin Brownf660fb42016-09-09 12:04:00 -07002067 ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev,
2068 allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002069 cds_ssr_unprotect(__func__);
2070
2071 return ret;
2072}
2073
2074/**
2075 * __wlan_hdd_cfg80211_set_txpower() - set TX power
2076 * @wiphy: Pointer to wiphy
2077 * @wdev: Pointer to network device
2078 * @type: TX power setting type
2079 * @dbm: TX power in dbm
2080 *
2081 * Return: 0 for success, non-zero for failure
2082 */
2083static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002085 enum nl80211_tx_power_setting type,
2086 int dbm)
2087{
2088 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
2089 tHalHandle hHal = NULL;
Anurag Chouhan6d760662016-02-20 16:05:43 +05302090 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
2091 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002092 int status;
2093
2094 ENTER();
2095
Anurag Chouhan6d760662016-02-20 16:05:43 +05302096 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002097 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002098 return -EINVAL;
2099 }
2100
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302101 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002102 TRACE_CODE_HDD_CFG80211_SET_TXPOWER,
2103 NO_SESSION, type));
2104
2105 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302106 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002107 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002108
2109 hHal = pHddCtx->hHal;
2110
2111 if (0 != sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, dbm)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002112 hdd_err("sme_cfg_set_int failed for tx power %hu",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002113 dbm);
2114 return -EIO;
2115 }
2116
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002117 hdd_debug("Set tx power level %d dbm", dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002118
2119 switch (type) {
2120 /* Automatically determine transmit power */
2121 case NL80211_TX_POWER_AUTOMATIC:
2122 /* Fall through */
2123 case NL80211_TX_POWER_LIMITED: /* Limit TX power by the mBm parameter */
2124 if (sme_set_max_tx_power(hHal, bssid, selfMac, dbm) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302125 QDF_STATUS_SUCCESS) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002126 hdd_err("Setting maximum tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002127 return -EIO;
2128 }
2129 break;
2130
2131 case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */
Jeff Johnsonc3273322016-07-06 15:28:17 -07002132 hdd_err("NL80211_TX_POWER_FIXED not supported");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002133 return -EOPNOTSUPP;
2134 break;
2135
2136 default:
Jeff Johnsonc3273322016-07-06 15:28:17 -07002137 hdd_err("Invalid power setting type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002138 return -EIO;
2139 }
2140
2141 EXIT();
2142 return 0;
2143}
2144
2145/**
2146 * wlan_hdd_cfg80211_set_txpower() - set TX power
2147 * @wiphy: Pointer to wiphy
2148 * @wdev: Pointer to network device
2149 * @type: TX power setting type
2150 * @dbm: TX power in dbm
2151 *
2152 * Return: 0 for success, non-zero for failure
2153 */
2154int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002155 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002156 enum nl80211_tx_power_setting type,
2157 int dbm)
2158{
2159 int ret;
2160 cds_ssr_protect(__func__);
2161 ret = __wlan_hdd_cfg80211_set_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002162 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002163 type, dbm);
2164 cds_ssr_unprotect(__func__);
2165
2166 return ret;
2167}
2168
2169/**
2170 * __wlan_hdd_cfg80211_get_txpower() - get TX power
2171 * @wiphy: Pointer to wiphy
2172 * @wdev: Pointer to network device
2173 * @dbm: Pointer to TX power in dbm
2174 *
2175 * Return: 0 for success, non-zero for failure
2176 */
2177static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002178 struct wireless_dev *wdev,
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08002179 int *dbm, hdd_adapter_t *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002180{
2181
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002182 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
2183 int status;
2184
2185 ENTER();
2186
Anurag Chouhan6d760662016-02-20 16:05:43 +05302187 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002188 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002189 return -EINVAL;
2190 }
2191
2192 status = wlan_hdd_validate_context(pHddCtx);
2193 if (0 != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194 *dbm = 0;
2195 return status;
2196 }
2197
Arun Khandavalli99286452016-08-22 12:13:41 +05302198 /* Validate adapter sessionId */
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302199 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2200 hdd_err("invalid session id: %d", adapter->sessionId);
Arun Khandavalli99286452016-08-22 12:13:41 +05302201 return -ENOTSUPP;
2202 }
2203
2204 mutex_lock(&pHddCtx->iface_change_lock);
2205 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
2206 mutex_unlock(&pHddCtx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002207 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05302208 /* Send cached data to upperlayer*/
2209 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
2210 return 0;
2211 }
2212 mutex_unlock(&pHddCtx->iface_change_lock);
2213
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302214 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302215 TRACE_CODE_HDD_CFG80211_GET_TXPOWER,
Arun Khandavalli99286452016-08-22 12:13:41 +05302216 adapter->sessionId, adapter->device_mode));
2217 wlan_hdd_get_class_astats(adapter);
2218 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002219
2220 EXIT();
2221 return 0;
2222}
2223
2224/**
2225 * wlan_hdd_cfg80211_get_txpower() - cfg80211 get power handler function
2226 * @wiphy: Pointer to wiphy structure.
2227 * @wdev: Pointer to wireless_dev structure.
2228 * @dbm: dbm
2229 *
2230 * This is the cfg80211 get txpower handler function which invokes
2231 * the internal function @__wlan_hdd_cfg80211_get_txpower with
2232 * SSR protection.
2233 *
2234 * Return: 0 for success, error number on failure.
2235 */
2236int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002237 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002238 int *dbm)
2239{
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08002240 int ret = -ENOTSUPP;
2241 struct net_device *ndev = wdev->netdev;
2242 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002243
2244 cds_ssr_protect(__func__);
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08002245 if (adapter->sessionId != HDD_SESSION_ID_INVALID)
2246 ret = __wlan_hdd_cfg80211_get_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002247 wdev,
Srinivas Girigowda86ecc012017-03-10 12:26:57 -08002248 dbm, adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002249 cds_ssr_unprotect(__func__);
2250
2251 return ret;
2252}
Kapil Gupta6213c012016-09-02 19:39:09 +05302253
2254/**
2255 * hdd_set_qpower_config() - set qpower config to firmware
2256 * @adapter: HDD adapter
2257 * @qpower: new qpower config value
2258 *
2259 * Return: 0 on success; Errno on failure
2260 */
2261int hdd_set_qpower_config(hdd_context_t *hddctx, hdd_adapter_t *adapter,
Dustin Brown10a7b712016-10-07 10:31:16 -07002262 u8 qpower)
Kapil Gupta6213c012016-09-02 19:39:09 +05302263{
Dustin Brown10a7b712016-10-07 10:31:16 -07002264 QDF_STATUS status;
Kapil Gupta6213c012016-09-02 19:39:09 +05302265
2266 if (!hddctx->config->enablePowersaveOffload) {
2267 hdd_err("qpower is disabled in configuration");
2268 return -EINVAL;
2269 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002270
Kapil Gupta6213c012016-09-02 19:39:09 +05302271 if (qpower > PS_DUTY_CYCLING_QPOWER ||
2272 qpower < PS_LEGACY_NODEEPSLEEP) {
Dustin Brown10a7b712016-10-07 10:31:16 -07002273 hdd_err("invalid qpower value: %d", qpower);
Kapil Gupta6213c012016-09-02 19:39:09 +05302274 return -EINVAL;
2275 }
Kapil Gupta6213c012016-09-02 19:39:09 +05302276
Kiran Kumar Lokere7006e0a2017-03-07 19:28:36 -08002277 if (hddctx->config->nMaxPsPoll) {
2278 if ((qpower == PS_QPOWER_NODEEPSLEEP) ||
2279 (qpower == PS_LEGACY_NODEEPSLEEP))
2280 qpower = PS_LEGACY_NODEEPSLEEP;
2281 else
2282 qpower = PS_LEGACY_DEEPSLEEP;
2283 hdd_info("Qpower disabled, %d", qpower);
2284 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002285 status = wma_set_qpower_config(adapter->sessionId, qpower);
2286 if (status != QDF_STATUS_SUCCESS) {
2287 hdd_err("failed to configure qpower: %d", status);
2288 return -EINVAL;
Kapil Gupta6213c012016-09-02 19:39:09 +05302289 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002290
Kapil Gupta6213c012016-09-02 19:39:09 +05302291 return 0;
2292}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002293
Dustin Brown54096432017-02-23 13:00:44 -08002294
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002295#ifdef WLAN_SUSPEND_RESUME_TEST
Dustin Brownbc81a472016-10-26 16:56:59 -07002296static struct net_device *g_dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002297static struct wiphy *g_wiphy;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002298static enum wow_resume_trigger g_resume_trigger;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002299
2300#define HDD_FA_SUSPENDED_BIT (0)
2301static unsigned long fake_apps_state;
2302
Dustin Brownd53d1a82016-10-03 12:57:33 -07002303/**
2304 * __hdd_wlan_fake_apps_resume() - The core logic for
2305 * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(),
2306 * which is only need for non-irq resume
Dustin Brownbc81a472016-10-26 16:56:59 -07002307 * @wiphy: the kernel wiphy struct for the device being resumed
2308 * @dev: the kernel net_device struct for the device being resumed
Dustin Brownd53d1a82016-10-03 12:57:33 -07002309 *
Dustin Brownbc81a472016-10-26 16:56:59 -07002310 * Return: none, calls QDF_BUG() on failure
Dustin Brownd53d1a82016-10-03 12:57:33 -07002311 */
Dustin Brownbc81a472016-10-26 16:56:59 -07002312static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy,
2313 struct net_device *dev)
Dustin Brownd53d1a82016-10-03 12:57:33 -07002314{
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002315 struct hif_opaque_softc *hif_ctx;
Dustin Brownddb59702017-01-12 16:20:31 -08002316 qdf_device_t qdf_dev;
Dustin Brownd53d1a82016-10-03 12:57:33 -07002317
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002318 hdd_debug("Unit-test resume WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002319
2320 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2321 if (!qdf_dev) {
2322 hdd_err("Failed to get QDF device context");
2323 QDF_BUG(0);
2324 return;
2325 }
2326
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002327 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2328 if (!hif_ctx) {
2329 hdd_err("Failed to get HIF context");
2330 return;
2331 }
2332
Dustin Brownd53d1a82016-10-03 12:57:33 -07002333 if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002334 hdd_debug("Not unit-test suspended; Nothing to do");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002335 return;
2336 }
2337
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002338 /* simulate kernel disable irqs */
2339 QDF_BUG(!hif_apps_wake_irq_disable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002340
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002341 QDF_BUG(!wlan_hdd_bus_resume_noirq());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002342
2343 /* simulate kernel enable irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002344 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002345
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002346 QDF_BUG(!wlan_hdd_bus_resume());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002347
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002348 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
2349
2350 if (g_resume_trigger == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2351 hif_vote_link_down(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002352
2353 dev->watchdog_timeo = HDD_TX_TIMEOUT;
Dustin Brown562b9672016-12-22 15:25:33 -08002354
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002355 hdd_debug("Unit-test resume succeeded");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002356}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002357
2358/**
2359 * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming
2360 * from unit-test initiated suspend from irq wakeup signal
2361 * @val: interrupt val
2362 *
2363 * Resume wlan after getting very 1st CE interrupt from target
2364 *
2365 * Return: none
2366 */
2367static void hdd_wlan_fake_apps_resume_irq_callback(uint32_t val)
2368{
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002369 hdd_debug("Trigger unit-test resume WLAN; val: 0x%x", val);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002370
2371 QDF_BUG(g_wiphy);
Dustin Brownbc81a472016-10-26 16:56:59 -07002372 QDF_BUG(g_dev);
2373 __hdd_wlan_fake_apps_resume(g_wiphy, g_dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002374 g_wiphy = NULL;
Dustin Brownbc81a472016-10-26 16:56:59 -07002375 g_dev = NULL;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002376}
2377
Dustin Brown54096432017-02-23 13:00:44 -08002378int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev,
2379 enum wow_interface_pause pause_setting,
2380 enum wow_resume_trigger resume_setting)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002381{
Dustin Brownddb59702017-01-12 16:20:31 -08002382 qdf_device_t qdf_dev;
2383 struct hif_opaque_softc *hif_ctx;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002384 int errno;
Dustin Brown54096432017-02-23 13:00:44 -08002385 struct wow_enable_params wow_params = {
2386 .is_unit_test = true,
2387 .interface_pause = pause_setting,
2388 .resume_trigger = resume_setting
2389 };
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002390
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002391 hdd_debug("Unit-test suspend WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002392
Dustin Brown54096432017-02-23 13:00:44 -08002393 if (pause_setting < WOW_INTERFACE_PAUSE_DEFAULT ||
2394 pause_setting >= WOW_INTERFACE_PAUSE_COUNT) {
2395 hdd_err("Invalid interface pause %d (expected range [0, 2])",
2396 pause_setting);
2397 return -EINVAL;
2398 }
2399
2400 if (resume_setting < WOW_RESUME_TRIGGER_DEFAULT ||
2401 resume_setting >= WOW_RESUME_TRIGGER_COUNT) {
2402 hdd_err("Invalid resume trigger %d (expected range [0, 2])",
2403 resume_setting);
2404 return -EINVAL;
2405 }
2406
Dustin Brownddb59702017-01-12 16:20:31 -08002407 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2408 if (!qdf_dev) {
2409 hdd_err("Failed to get QDF device context");
2410 return -EINVAL;
2411 }
2412
2413 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2414 if (!hif_ctx) {
2415 hdd_err("Failed to get HIF context");
2416 return -EINVAL;
2417 }
2418
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002419 if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002420 hdd_debug("Already unit-test suspended; Nothing to do");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002421 return 0;
2422 }
2423
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002424 /* pci link is needed to wakeup from HTC wakeup trigger */
2425 if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2426 hif_vote_link_up(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002427
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002428 errno = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL);
2429 if (errno)
2430 goto link_down;
2431
2432 errno = wlan_hdd_unit_test_bus_suspend(wow_params);
2433 if (errno)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002434 goto cfg80211_resume;
2435
2436 /* simulate kernel disabling irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002437 errno = hif_apps_irqs_disable(hif_ctx);
2438 if (errno)
2439 goto bus_resume;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002440
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002441 errno = wlan_hdd_bus_suspend_noirq();
2442 if (errno)
2443 goto enable_irqs;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002444
Dustin Brownbc81a472016-10-26 16:56:59 -07002445 /* pass wiphy/dev to callback via global variables */
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002446 g_wiphy = wiphy;
Dustin Brownbc81a472016-10-26 16:56:59 -07002447 g_dev = dev;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002448 g_resume_trigger = resume_setting;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002449 hif_fake_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback);
2450
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002451 /* re-enable wake irq */
2452 errno = hif_apps_wake_irq_enable(hif_ctx);
2453 if (errno)
2454 goto fake_apps_resume;
2455
Dustin Brownbc81a472016-10-26 16:56:59 -07002456 /*
2457 * Tell the kernel not to worry if TX queues aren't moving. This is
2458 * expected since we are suspending the wifi hardware, but not APPS
2459 */
2460 dev->watchdog_timeo = INT_MAX;
2461
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002462 hdd_debug("Unit-test suspend succeeded");
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002463
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002464 return 0;
2465
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002466fake_apps_resume:
2467 hif_fake_apps_resume(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002468
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002469enable_irqs:
2470 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
2471
2472bus_resume:
2473 QDF_BUG(!wlan_hdd_bus_resume());
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002474
2475cfg80211_resume:
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002476 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002477
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002478link_down:
2479 hif_vote_link_down(hif_ctx);
2480
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002481 clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state);
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002482 hdd_err("Unit-test suspend failed: %d", errno);
2483
2484 return errno;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002485}
2486
Dustin Brownbc81a472016-10-26 16:56:59 -07002487int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002488{
Dustin Brownddb59702017-01-12 16:20:31 -08002489 struct hif_opaque_softc *hif_ctx;
2490
2491 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2492 if (!hif_ctx) {
2493 hdd_err("Failed to get HIF context");
2494 return -EINVAL;
2495 }
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002496
2497 hif_fake_apps_resume(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002498 __hdd_wlan_fake_apps_resume(wiphy, dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002499
2500 return 0;
2501}
2502#endif