blob: f8b57f37ae50739c7681d08a6b10242466880681 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Jingxiang Geb49aa302018-01-17 20:54:15 +08002 * Copyright (c) 2012-2018 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"
Dustin Brown0f8dc3d2017-06-01 14:37:26 -070075#include "hif_unit_test_suspend.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080076#include "sme_power_save_api.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080077#include "wlan_policy_mgr_api.h"
Dhanashri Atreb08959a2016-03-01 17:28:03 -080078#include "cdp_txrx_flow_ctrl_v2.h"
Yuanyuan Liu13738502016-04-06 17:41:37 -070079#include "pld_common.h"
Rajeev Kumar9bb2e852016-09-24 12:29:25 -070080#include "wlan_hdd_driver_ops.h"
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +053081#include <wlan_logging_sock_svc.h>
Krunal Sonid32c6bc2016-10-18 18:00:21 -070082#include "scheduler_api.h"
yeshwanth sriram guntuka310b3ac2016-11-15 23:25:26 +053083#include "cds_utils.h"
Hanumanth Reddy Pothula3def8942017-10-05 16:19:36 +053084#include "wlan_hdd_packet_filter_api.h"
Arunk Khandavallif0c0d762017-12-07 10:18:50 +053085#include "wlan_cfg80211_scan.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080086
87/* Preprocessor definitions and constants */
Yue Ma5fe30dd2017-05-02 15:47:40 -070088#ifdef QCA_WIFI_NAPIER_EMULATION
89#define HDD_SSR_BRING_UP_TIME 3000000
90#else
Yue Ma4ea4f052015-10-27 12:25:27 -070091#define HDD_SSR_BRING_UP_TIME 30000
Yue Ma5fe30dd2017-05-02 15:47:40 -070092#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080093
94/* Type declarations */
95
Abhishek Singhbaea27d2016-04-27 13:29:30 +053096#ifdef FEATURE_WLAN_DIAG_SUPPORT
97/**
98 * hdd_wlan_suspend_resume_event()- send suspend/resume state
99 * @state: suspend/resume state
100 *
101 * This Function send send suspend resume state diag event
102 *
103 * Return: void.
104 */
105void hdd_wlan_suspend_resume_event(uint8_t state)
106{
107 WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend);
108 qdf_mem_zero(&suspend_state, sizeof(suspend_state));
109
110 suspend_state.state = state;
111 WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
112}
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530113
114/**
115 * hdd_wlan_offload_event()- send offloads event
116 * @type: offload type
117 * @state: enabled or disabled
118 *
119 * This Function send offloads enable/disable diag event
120 *
121 * Return: void.
122 */
123
124void hdd_wlan_offload_event(uint8_t type, uint8_t state)
125{
126 WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req);
127 qdf_mem_zero(&host_offload, sizeof(host_offload));
128
129 host_offload.offload_type = type;
130 host_offload.state = state;
131
132 WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ);
133}
Abhishek Singhbaea27d2016-04-27 13:29:30 +0530134#endif
135
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800136/**
Mukul Sharma3d36c392017-01-18 18:39:12 +0530137 * hdd_enable_gtk_offload() - enable GTK offload
138 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800139 *
Mukul Sharma3d36c392017-01-18 18:39:12 +0530140 * Central function to enable GTK offload.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800141 *
142 * Return: nothing
143 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700144static void hdd_enable_gtk_offload(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800145{
Mukul Sharma3d36c392017-01-18 18:39:12 +0530146 QDF_STATUS status;
Jeff Johnson4f7f7c62017-10-05 08:53:41 -0700147
Mukul Sharma3d36c392017-01-18 18:39:12 +0530148 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
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700155 * @adapter: pointer to the adapter
Mukul Sharma3d36c392017-01-18 18:39:12 +0530156 *
157 * Central function to disable GTK offload.
158 *
159 * Return: nothing
160 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700161static void hdd_disable_gtk_offload(struct hdd_adapter *adapter)
Mukul Sharma3d36c392017-01-18 18:39:12 +0530162{
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 =
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530168 wlan_hdd_cfg80211_update_replay_counter_cb;
Mukul Sharma3d36c392017-01-18 18:39:12 +0530169 /* 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,
Dustin Brownf13b8c32017-05-19 17:23:08 -0700200 unsigned long data, void *arg)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800201{
202 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
203 struct net_device *ndev = ifa->idev->dev;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700204 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700205 struct hdd_context *hdd_ctx;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700206 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207
Jeff Johnson158c8d02016-10-31 13:11:48 -0700208 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530209
Dustin Brownf13b8c32017-05-19 17:23:08 -0700210 errno = hdd_validate_adapter(adapter);
211 if (errno)
212 goto exit;
213
214 if (adapter->dev == ndev &&
215 (adapter->device_mode == QDF_STA_MODE ||
216 adapter->device_mode == QDF_P2P_CLIENT_MODE ||
217 adapter->device_mode == QDF_NDI_MODE)) {
218 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
219 errno = wlan_hdd_validate_context(hdd_ctx);
220 if (errno)
221 goto exit;
222
Nachiket Kukadec9045fe2017-06-19 15:14:43 +0530223 /* Ignore if the interface is down */
224 if (!(ndev->flags & IFF_UP)) {
225 hdd_err("Rcvd change addr request on %s(flags 0x%X)",
226 ndev->name, ndev->flags);
227 hdd_err("NETDEV Interface is down, ignoring...");
228 goto exit;
229 }
230
Dustin Brownf13b8c32017-05-19 17:23:08 -0700231 hdd_debug("invoking sme_dhcp_done_ind");
Jeff Johnson1b780e42017-10-31 14:11:45 -0700232 sme_dhcp_done_ind(hdd_ctx->hHal, adapter->session_id);
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700233 schedule_work(&adapter->ipv6_notifier_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800234 }
235
Dustin Brownf13b8c32017-05-19 17:23:08 -0700236exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530237 EXIT();
Dustin Brownf13b8c32017-05-19 17:23:08 -0700238
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800239 return NOTIFY_DONE;
240}
241
242/**
243 * wlan_hdd_ipv6_changed() - IPv6 change notifier callback
244 * @nb: pointer to notifier block
245 * @data: data
246 * @arg: arg
247 *
248 * This is the IPv6 notifier callback function gets invoked
249 * if any change in IP and then invoke the function @__wlan_hdd_ipv6_changed
250 * to reconfigure the offload parameters.
251 *
252 * Return: 0 on success, error number otherwise.
253 */
254int wlan_hdd_ipv6_changed(struct notifier_block *nb,
255 unsigned long data, void *arg)
256{
257 int ret;
258
259 cds_ssr_protect(__func__);
260 ret = __wlan_hdd_ipv6_changed(nb, data, arg);
261 cds_ssr_unprotect(__func__);
262
263 return ret;
264}
265
266/**
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530267 * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses
268 * @idev: pointer to net device
269 * @ipv6addr: destination array to fill IPv6 addresses
270 * @ipv6addr_type: IPv6 Address type
271 * @count: number of IPv6 addresses
272 *
273 * This is the IPv6 utility function to populate unicast addresses.
274 *
275 * Return: 0 on success, error number otherwise.
276 */
277static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
278 uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN],
279 uint8_t *ipv6addr_type, uint32_t *count)
280{
281 struct inet6_ifaddr *ifa;
282 struct list_head *p;
283 uint32_t scope;
284
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700285 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530286 list_for_each(p, &idev->addr_list) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530287 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700288 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530289 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700290 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530291 ifa = list_entry(p, struct inet6_ifaddr, if_list);
292 if (ifa->flags & IFA_F_DADFAILED)
293 continue;
294 scope = ipv6_addr_src_scope(&ifa->addr);
295 switch (scope) {
296 case IPV6_ADDR_SCOPE_GLOBAL:
297 case IPV6_ADDR_SCOPE_LINKLOCAL:
298 qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
299 sizeof(ifa->addr.s6_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530300 ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE;
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800301 hdd_debug("Index %d scope = %s UC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530302 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
303 "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
304 *count += 1;
305 break;
306 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800307 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530308 }
309 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700310
311 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530312 return 0;
313}
314
315/**
316 * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses
317 * @idev: pointer to net device
318 * @ipv6addr: destination array to fill IPv6 addresses
319 * @ipv6addr_type: IPv6 Address type
320 * @count: number of IPv6 addresses
321 *
322 * This is the IPv6 utility function to populate anycast addresses.
323 *
324 * Return: 0 on success, error number otherwise.
325 */
326static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
327 uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN],
328 uint8_t *ipv6addr_type, uint32_t *count)
329{
330 struct ifacaddr6 *ifaca;
331 uint32_t scope;
332
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700333 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530334 for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530335 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700336 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530337 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700338 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530339 /* For anycast addr no DAD */
340 scope = ipv6_addr_src_scope(&ifaca->aca_addr);
341 switch (scope) {
342 case IPV6_ADDR_SCOPE_GLOBAL:
343 case IPV6_ADDR_SCOPE_LINKLOCAL:
344 qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
345 sizeof(ifaca->aca_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530346 ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE;
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800347 hdd_debug("Index %d scope = %s AC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530348 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
349 "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
350 *count += 1;
351 break;
352 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800353 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530354 }
355 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700356
357 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530358 return 0;
359}
360
Jeff Johnson75b737d2017-08-29 14:24:41 -0700361void hdd_enable_ns_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530362 enum pmo_offload_trigger trigger)
Dustin Brown2444ee62016-09-06 17:20:36 -0700363{
364 struct inet6_dev *in6_dev;
Dustin Brown2444ee62016-09-06 17:20:36 -0700365 QDF_STATUS status;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700366 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530367 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
368 struct pmo_ns_req *ns_req = NULL;
369 int err;
370
371 ENTER();
372 if (!psoc) {
373 hdd_err("psoc is NULL");
374 goto out;
375 }
Dustin Brown2444ee62016-09-06 17:20:36 -0700376
377 in6_dev = __in6_dev_get(adapter->dev);
378 if (NULL == in6_dev) {
379 hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530380 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700381 }
382
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530383 ns_req = qdf_mem_malloc(sizeof(*ns_req));
384 if (!ns_req) {
385 hdd_err("fail to allocate ns_req");
386 goto out;
387 }
388
389 ns_req->psoc = psoc;
Jeff Johnson1b780e42017-10-31 14:11:45 -0700390 ns_req->vdev_id = adapter->session_id;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530391 ns_req->trigger = trigger;
392 ns_req->count = 0;
393
Dustin Brown2444ee62016-09-06 17:20:36 -0700394 /* Unicast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530395 err = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
396 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700397 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530398 hdd_disable_ns_offload(adapter, trigger);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530399 hdd_debug("Max supported addresses: disabling NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530400 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700401 }
402
403 /* Anycast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530404 err = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
405 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700406 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530407 hdd_disable_ns_offload(adapter, trigger);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530408 hdd_debug("Max supported addresses: disabling NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530409 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700410 }
411
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530412 /* cache ns request */
413 status = pmo_ucfg_cache_ns_offload_req(ns_req);
414 if (status != QDF_STATUS_SUCCESS) {
415 hdd_err("Failed to cache ns request status: %d", status);
416 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700417 }
418
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530419 /* enable ns request */
420 status = pmo_ucfg_enable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
421 if (status != QDF_STATUS_SUCCESS)
Dustin Brown2444ee62016-09-06 17:20:36 -0700422 hdd_err("Failed to enable HostOffload feature with status: %d",
423 status);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530424 else
425 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
426out:
427 if (ns_req)
428 qdf_mem_free(ns_req);
429 EXIT();
430
Dustin Brown2444ee62016-09-06 17:20:36 -0700431}
432
Jeff Johnson75b737d2017-08-29 14:24:41 -0700433void hdd_disable_ns_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530434 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800435{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530436 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800437
438 ENTER();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530439 status = pmo_ucfg_flush_ns_offload_req(adapter->hdd_vdev);
440 if (status != QDF_STATUS_SUCCESS) {
441 hdd_err("Failed to flush NS Offload");
442 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800443 }
444
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530445 status = pmo_ucfg_disable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
446 if (status != QDF_STATUS_SUCCESS)
447 hdd_err("Failed to disable NS Offload");
Dustin Brown2444ee62016-09-06 17:20:36 -0700448 else
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530449 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD,
450 SIR_OFFLOAD_DISABLE);
451out:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800452 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530453
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800454}
455
456/**
457 * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function
458 * @work: registered work item
459 *
460 * This function performs the work initially trigged by a callback
461 * from the IPv6 netdev notifier. Since this means there has been a
462 * change in IPv6 state for the interface, the NS offload is
463 * reconfigured.
464 *
465 * Return: None
466 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700467static void __hdd_ipv6_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800468{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700469 struct hdd_context *hdd_ctx;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700470 struct hdd_adapter *adapter;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700471 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800472
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530473 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700475 adapter = container_of(work, struct hdd_adapter, ipv6_notifier_work);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700476 errno = hdd_validate_adapter(adapter);
477 if (errno)
478 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800479
Dustin Brownf13b8c32017-05-19 17:23:08 -0700480 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
481 errno = wlan_hdd_validate_context(hdd_ctx);
482 if (errno)
483 goto exit;
484
485 hdd_enable_ns_offload(adapter, pmo_ipv6_change_notify);
486
487exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530488 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800489}
490
491/**
492 * hdd_ipv6_notifier_work_queue() - IP V6 change notifier work handler
493 * @work: Pointer to work context
494 *
495 * Return: none
496 */
497void hdd_ipv6_notifier_work_queue(struct work_struct *work)
498{
499 cds_ssr_protect(__func__);
500 __hdd_ipv6_notifier_work_queue(work);
501 cds_ssr_unprotect(__func__);
502}
503
Jeff Johnson75b737d2017-08-29 14:24:41 -0700504static void hdd_enable_hw_filter(struct hdd_adapter *adapter)
Dustin Brown1224e212017-05-12 14:02:12 -0700505{
506 QDF_STATUS status;
507
508 ENTER();
509
510 status = pmo_ucfg_enable_hw_filter_in_fwr(adapter->hdd_vdev);
511 if (status != QDF_STATUS_SUCCESS)
512 hdd_info("Failed to enable hardware filter");
513
514 EXIT();
515}
516
Jeff Johnson75b737d2017-08-29 14:24:41 -0700517static void hdd_disable_hw_filter(struct hdd_adapter *adapter)
Dustin Brown1224e212017-05-12 14:02:12 -0700518{
519 QDF_STATUS status;
520
521 ENTER();
522
523 status = pmo_ucfg_disable_hw_filter_in_fwr(adapter->hdd_vdev);
524 if (status != QDF_STATUS_SUCCESS)
525 hdd_info("Failed to disable hardware filter");
526
527 EXIT();
528}
529
Jeff Johnson75b737d2017-08-29 14:24:41 -0700530void hdd_enable_host_offloads(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530531 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800532{
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530533 ENTER();
534
Rajeev Kumarec1194d2017-11-16 17:30:01 -0800535 if (!ucfg_pmo_is_vdev_supports_offload(adapter->hdd_vdev)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530536 hdd_info("offload is not supported on this vdev opmode: %d",
537 adapter->device_mode);
538 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800539 }
540
Rajeev Kumar9084cc82017-10-31 14:32:08 -0700541 if (!ucfg_pmo_is_vdev_connected(adapter->hdd_vdev)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530542 hdd_info("vdev is not connected");
543 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800544 }
545
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530546 hdd_info("enable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530547 hdd_enable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530548 hdd_enable_arp_offload(adapter, trigger);
549 hdd_enable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530550 hdd_enable_mc_addr_filtering(adapter, trigger);
Dustin Brown1224e212017-05-12 14:02:12 -0700551 hdd_enable_hw_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530552out:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530553 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530554
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800555}
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530556
Jeff Johnson75b737d2017-08-29 14:24:41 -0700557void hdd_disable_host_offloads(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530558 enum pmo_offload_trigger trigger)
559{
560 ENTER();
561
Rajeev Kumarec1194d2017-11-16 17:30:01 -0800562 if (!ucfg_pmo_is_vdev_supports_offload(adapter->hdd_vdev)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530563 hdd_info("offload is not supported on this vdev opmode: %d",
564 adapter->device_mode);
565 goto out;
566 }
567
Rajeev Kumar9084cc82017-10-31 14:32:08 -0700568 if (!ucfg_pmo_is_vdev_connected(adapter->hdd_vdev)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530569 hdd_info("vdev is not connected");
570 goto out;
571 }
572
573 hdd_info("disable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530574 hdd_disable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530575 hdd_disable_arp_offload(adapter, trigger);
576 hdd_disable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530577 hdd_disable_mc_addr_filtering(adapter, trigger);
Dustin Brown1224e212017-05-12 14:02:12 -0700578 hdd_disable_hw_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530579out:
580 EXIT();
581
582}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800583
584/**
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800585 * hdd_lookup_ifaddr() - Lookup interface address data by name
586 * @adapter: the adapter whose name should be searched for
587 *
588 * return in_ifaddr pointer on success, NULL for failure
589 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700590static struct in_ifaddr *hdd_lookup_ifaddr(struct hdd_adapter *adapter)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800591{
592 struct in_ifaddr *ifa;
593 struct in_device *in_dev;
594
595 if (!adapter) {
596 hdd_err("adapter is null");
597 return NULL;
598 }
599
600 in_dev = __in_dev_get_rtnl(adapter->dev);
601 if (!in_dev) {
602 hdd_err("Failed to get in_device");
603 return NULL;
604 }
605
606 /* lookup address data by interface name */
607 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
608 if (!strcmp(adapter->dev->name, ifa->ifa_label))
609 return ifa;
610 }
611
612 return NULL;
613}
614
615/**
616 * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address
617 * @adapter: the adapter whose IPv4 address is desired
618 * @ipv4_addr: the address of the array to copy the IPv4 address into
619 *
620 * return: zero for success; non-zero for failure
621 */
Jeff Johnsond6d1f632017-10-06 20:06:10 -0700622static int hdd_populate_ipv4_addr(struct hdd_adapter *adapter,
623 uint8_t *ipv4_addr)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800624{
625 struct in_ifaddr *ifa;
626 int i;
627
628 if (!adapter) {
629 hdd_err("adapter is null");
630 return -EINVAL;
631 }
632
633 if (!ipv4_addr) {
634 hdd_err("ipv4_addr is null");
635 return -EINVAL;
636 }
637
638 ifa = hdd_lookup_ifaddr(adapter);
639 if (!ifa || !ifa->ifa_local) {
640 hdd_err("ipv4 address not found");
641 return -EINVAL;
642 }
643
644 /* convert u32 to byte array */
645 for (i = 0; i < 4; i++)
646 ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff;
647
648 return 0;
649}
650
651/**
652 * hdd_set_grat_arp_keepalive() - Enable grat APR keepalive
653 * @adapter: the HDD adapter to configure
654 *
655 * This configures gratuitous APR keepalive based on the adapter's current
656 * connection information, specifically IPv4 address and BSSID
657 *
658 * return: zero for success, non-zero for failure
659 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700660static int hdd_set_grat_arp_keepalive(struct hdd_adapter *adapter)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800661{
662 QDF_STATUS status;
663 int exit_code;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700664 struct hdd_context *hdd_ctx;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700665 struct hdd_station_ctx *sta_ctx;
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800666 tSirKeepAliveReq req = {
667 .packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP,
Dustin Brownce5b3d32018-01-17 15:07:38 -0800668 .dest_macaddr = QDF_MAC_ADDR_BCAST_INIT,
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800669 };
670
671 if (!adapter) {
672 hdd_err("adapter is null");
673 return -EINVAL;
674 }
675
676 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
677 if (!hdd_ctx) {
678 hdd_err("hdd_ctx is null");
679 return -EINVAL;
680 }
681
682 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
683 if (!sta_ctx) {
684 hdd_err("sta_ctx is null");
685 return -EINVAL;
686 }
687
688 exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr);
689 if (exit_code) {
690 hdd_err("Failed to populate ipv4 address");
691 return exit_code;
692 }
693
Dustin Brown6b4643d2017-02-09 12:19:28 -0800694 /* according to RFC5227, sender/target ip address should be the same */
695 qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr,
696 sizeof(req.destIpv4Addr));
697
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800698 qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssId);
699 req.timePeriod = hdd_ctx->config->infraStaKeepAlivePeriod;
Jeff Johnson1b780e42017-10-31 14:11:45 -0700700 req.sessionId = adapter->session_id;
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800701
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800702 hdd_debug("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u",
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800703 req.hostIpv4Addr[0], req.hostIpv4Addr[1],
704 req.hostIpv4Addr[2], req.hostIpv4Addr[3]);
705
706 status = sme_set_keep_alive(hdd_ctx->hHal, req.sessionId, &req);
707 if (QDF_IS_STATUS_ERROR(status)) {
708 hdd_err("Failed to set keepalive");
709 return qdf_status_to_os_return(status);
710 }
711
712 return 0;
713}
714
715/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800716 * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function
717 * @work: registered work item
718 *
719 * This function performs the work initially trigged by a callback
720 * from the IPv4 netdev notifier. Since this means there has been a
721 * change in IPv4 state for the interface, the ARP offload is
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530722 * reconfigured. Also, Updates the HLP IE info with IP address info
723 * to fw if LFR3 is enabled
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800724 *
725 * Return: None
726 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700727static void __hdd_ipv4_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800728{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700729 struct hdd_context *hdd_ctx;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700730 struct hdd_adapter *adapter;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700731 int errno;
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530732 struct hdd_wext_state *wext_state;
733 tCsrRoamProfile *roam_profile;
734 struct in_ifaddr *ifa;
Dustin Brownb6b0f182017-03-08 13:08:27 -0800735
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530736 ENTER();
Dustin Brownb6b0f182017-03-08 13:08:27 -0800737
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700738 adapter = container_of(work, struct hdd_adapter, ipv4_notifier_work);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700739 errno = hdd_validate_adapter(adapter);
740 if (errno)
741 goto exit;
Dustin Brownb6b0f182017-03-08 13:08:27 -0800742
743 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700744 errno = wlan_hdd_validate_context(hdd_ctx);
745 if (errno)
746 goto exit;
747
748 hdd_enable_arp_offload(adapter, pmo_ipv4_change_notify);
749
Dustin Brownb6b0f182017-03-08 13:08:27 -0800750 if (hdd_ctx->config->sta_keepalive_method == HDD_STA_KEEPALIVE_GRAT_ARP)
751 hdd_set_grat_arp_keepalive(adapter);
752
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530753 hdd_debug("FILS Roaming support: %d",
754 hdd_ctx->is_fils_roaming_supported);
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530755 wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
756 roam_profile = &wext_state->roamProfile;
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530757
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530758 ifa = hdd_lookup_ifaddr(adapter);
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530759 if (ifa && hdd_ctx->is_fils_roaming_supported)
Jeff Johnson1b780e42017-10-31 14:11:45 -0700760 sme_send_hlp_ie_info(hdd_ctx->hHal, adapter->session_id,
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530761 roam_profile, ifa->ifa_local);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700762exit:
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530763 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800764}
765
766/**
767 * hdd_ipv4_notifier_work_queue() - IP V4 change notifier work handler
768 * @work: Pointer to work context
769 *
770 * Return: none
771 */
772void hdd_ipv4_notifier_work_queue(struct work_struct *work)
773{
774 cds_ssr_protect(__func__);
775 __hdd_ipv4_notifier_work_queue(work);
776 cds_ssr_unprotect(__func__);
777}
778
779/**
780 * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function
781 * @nb: notifier block that was registered with the kernel
782 * @data: (unused) generic data that was registered with the kernel
783 * @arg: (unused) generic argument that was registered with the kernel
784 *
785 * This is a callback function that is registered with the kernel via
786 * register_inetaddr_notifier() which allows the driver to be
787 * notified when there is an IPv4 address change.
788 *
789 * Return: NOTIFY_DONE to indicate we don't care what happens with
790 * other callbacks
791 */
792static int __wlan_hdd_ipv4_changed(struct notifier_block *nb,
793 unsigned long data, void *arg)
794{
795 struct in_ifaddr *ifa = (struct in_ifaddr *)arg;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800796 struct net_device *ndev = ifa->ifa_dev->dev;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700797 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700798 struct hdd_context *hdd_ctx;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700799 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800800
Jeff Johnson158c8d02016-10-31 13:11:48 -0700801 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530802
Dustin Brownf13b8c32017-05-19 17:23:08 -0700803 errno = hdd_validate_adapter(adapter);
804 if (errno)
805 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800806
Dustin Brownf13b8c32017-05-19 17:23:08 -0700807 if (adapter->dev == ndev &&
808 (adapter->device_mode == QDF_STA_MODE ||
809 adapter->device_mode == QDF_P2P_CLIENT_MODE ||
810 adapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800811
Dustin Brownf13b8c32017-05-19 17:23:08 -0700812 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
813 errno = wlan_hdd_validate_context(hdd_ctx);
814 if (errno)
815 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800816
Nachiket Kukadec9045fe2017-06-19 15:14:43 +0530817 /* Ignore if the interface is down */
818 if (!(ndev->flags & IFF_UP)) {
819 hdd_err("Rcvd change addr request on %s(flags 0x%X)",
820 ndev->name, ndev->flags);
821 hdd_err("NETDEV Interface is down, ignoring...");
822 goto exit;
823 }
Padma, Santhosh Kumar8392fb42017-03-17 12:35:27 +0530824 hdd_debug("invoking sme_dhcp_done_ind");
Jeff Johnson1b780e42017-10-31 14:11:45 -0700825 sme_dhcp_done_ind(hdd_ctx->hHal, adapter->session_id);
Abhishek Singhca408032016-09-13 15:26:12 +0530826
Dustin Brownf13b8c32017-05-19 17:23:08 -0700827 if (!hdd_ctx->config->fhostArpOffload) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800828 hdd_debug("Offload not enabled ARPOffload=%d",
Dustin Brownf13b8c32017-05-19 17:23:08 -0700829 hdd_ctx->config->fhostArpOffload);
830 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800831 }
832
Dustin Brownf13b8c32017-05-19 17:23:08 -0700833 ifa = hdd_lookup_ifaddr(adapter);
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800834 if (ifa && ifa->ifa_local)
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700835 schedule_work(&adapter->ipv4_notifier_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800836 }
Dustin Brownf13b8c32017-05-19 17:23:08 -0700837
838exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530839 EXIT();
Dustin Brownf13b8c32017-05-19 17:23:08 -0700840
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800841 return NOTIFY_DONE;
842}
843
844/**
845 * wlan_hdd_ipv4_changed() - IPv4 change notifier callback
846 * @nb: pointer to notifier block
847 * @data: data
848 * @arg: arg
849 *
850 * This is the IPv4 notifier callback function gets invoked
851 * if any change in IP and then invoke the function @__wlan_hdd_ipv4_changed
852 * to reconfigure the offload parameters.
853 *
854 * Return: 0 on success, error number otherwise.
855 */
856int wlan_hdd_ipv4_changed(struct notifier_block *nb,
857 unsigned long data, void *arg)
858{
859 int ret;
860
861 cds_ssr_protect(__func__);
862 ret = __wlan_hdd_ipv4_changed(nb, data, arg);
863 cds_ssr_unprotect(__func__);
864
865 return ret;
866}
867
868/**
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530869 * hdd_get_ipv4_local_interface() - get ipv4 local interafce from iface list
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700870 * @adapter: Adapter context for which ARP offload is to be configured
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800871 *
872 * Return:
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530873 * ifa - on successful operation,
874 * NULL - on failure of operation
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800875 */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530876static struct in_ifaddr *hdd_get_ipv4_local_interface(
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700877 struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530879 struct in_ifaddr **ifap = NULL;
880 struct in_ifaddr *ifa = NULL;
881 struct in_device *in_dev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800882
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700883 in_dev = __in_dev_get_rtnl(adapter->dev);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530884 if (in_dev) {
885 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
886 ifap = &ifa->ifa_next) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700887 if (!strcmp(adapter->dev->name, ifa->ifa_label)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530888 /* if match break */
889 return ifa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800890 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800891 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530892 }
893 ifa = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800894
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530895 return ifa;
896}
897
Jeff Johnson75b737d2017-08-29 14:24:41 -0700898void hdd_enable_arp_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530899 enum pmo_offload_trigger trigger)
900{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700901 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530902 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
903 QDF_STATUS status;
904 struct pmo_arp_req *arp_req = NULL;
905 struct in_ifaddr *ifa = NULL;
906
907 ENTER();
908 arp_req = qdf_mem_malloc(sizeof(*arp_req));
909 if (!arp_req) {
910 hdd_err("cannot allocate arp_req");
911 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800912 }
Jeff Johnson68755312017-02-10 11:46:55 -0800913
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530914 arp_req->psoc = psoc;
Jeff Johnson1b780e42017-10-31 14:11:45 -0700915 arp_req->vdev_id = adapter->session_id;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530916 arp_req->trigger = trigger;
Jeff Johnson68755312017-02-10 11:46:55 -0800917
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530918 ifa = hdd_get_ipv4_local_interface(adapter);
919 if (ifa && ifa->ifa_local) {
920 arp_req->ipv4_addr = (uint32_t)ifa->ifa_local;
921 status = pmo_ucfg_cache_arp_offload_req(arp_req);
922 if (status == QDF_STATUS_SUCCESS) {
923 status = pmo_ucfg_enable_arp_offload_in_fwr(
924 adapter->hdd_vdev, trigger);
925 if (status == QDF_STATUS_SUCCESS)
926 hdd_wlan_offload_event(
927 PMO_IPV4_ARP_REPLY_OFFLOAD,
928 PMO_OFFLOAD_ENABLE);
929 else
930 hdd_info("fail to enable arp offload in fwr");
931 } else
932 hdd_info("fail to cache arp offload request");
933 } else {
934 hdd_notice("IP Address is not assigned");
935 status = QDF_STATUS_NOT_INITIALIZED;
936 }
937out:
938 if (arp_req)
939 qdf_mem_free(arp_req);
940 EXIT();
941
942}
943
Jeff Johnson75b737d2017-08-29 14:24:41 -0700944void hdd_disable_arp_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530945 enum pmo_offload_trigger trigger)
946{
947 QDF_STATUS status;
948
949 ENTER();
950 status = pmo_ucfg_flush_arp_offload_req(adapter->hdd_vdev);
951 if (status != QDF_STATUS_SUCCESS) {
952 hdd_err("Failed to flush arp Offload");
953 goto out;
Jeff Johnson68755312017-02-10 11:46:55 -0800954 }
955
Jeff Johnsond6d1f632017-10-06 20:06:10 -0700956 status = pmo_ucfg_disable_arp_offload_in_fwr(adapter->hdd_vdev,
957 trigger);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530958 if (status == QDF_STATUS_SUCCESS)
959 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD,
960 PMO_OFFLOAD_DISABLE);
961 else
962 hdd_info("fail to disable arp offload");
963out:
964 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800965}
966
Jeff Johnson75b737d2017-08-29 14:24:41 -0700967void hdd_enable_mc_addr_filtering(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530968 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800969{
Jeff Johnson399c6272017-08-30 10:51:00 -0700970 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530971 QDF_STATUS status;
972 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800973
Ravi Joshi24477b72016-07-19 15:45:09 -0700974 ENTER();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530975 if (wlan_hdd_validate_context(hdd_ctx))
976 goto out;
Ravi Joshi24477b72016-07-19 15:45:09 -0700977
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530978 status = pmo_ucfg_enable_mc_addr_filtering_in_fwr(psoc,
Jeff Johnson1b780e42017-10-31 14:11:45 -0700979 adapter->session_id, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530980 if (status != QDF_STATUS_SUCCESS)
981 hdd_info("failed to enable mc list status %d", status);
982out:
Ravi Joshi24477b72016-07-19 15:45:09 -0700983 EXIT();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530984
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800985}
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530986
Jeff Johnson75b737d2017-08-29 14:24:41 -0700987void hdd_disable_mc_addr_filtering(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530988 enum pmo_offload_trigger trigger)
989{
Jeff Johnson399c6272017-08-30 10:51:00 -0700990 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530991 QDF_STATUS status = QDF_STATUS_SUCCESS;
992 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
993
994 ENTER();
995 if (wlan_hdd_validate_context(hdd_ctx))
996 goto out;
997
998 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
Jeff Johnson1b780e42017-10-31 14:11:45 -0700999 adapter->session_id, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301000 if (status != QDF_STATUS_SUCCESS)
1001 hdd_info("failed to disable mc list status %d", status);
1002out:
1003 EXIT();
1004
1005}
1006
1007int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config)
1008{
1009 QDF_STATUS status;
1010 int ret = 0;
1011
1012 ENTER();
1013 /* cache mc addr list */
1014 status = pmo_ucfg_cache_mc_addr_list(mc_list_config);
1015 if (status != QDF_STATUS_SUCCESS) {
1016 hdd_info("fail to cache mc list status %d", status);
1017 ret = -EINVAL;
1018 }
1019 EXIT();
1020
1021 return ret;
1022}
1023
Jeff Johnson75b737d2017-08-29 14:24:41 -07001024void hdd_disable_and_flush_mc_addr_list(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301025 enum pmo_offload_trigger trigger)
1026{
Jeff Johnson399c6272017-08-30 10:51:00 -07001027 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301028 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
1029 QDF_STATUS status = QDF_STATUS_SUCCESS;
1030
1031 ENTER();
1032 /* disable mc list first */
1033 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001034 adapter->session_id, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301035 if (status != QDF_STATUS_SUCCESS)
1036 hdd_info("fail to disable mc list");
1037
1038 /* flush mc list */
Jeff Johnson1b780e42017-10-31 14:11:45 -07001039 status = pmo_ucfg_flush_mc_addr_list(psoc, adapter->session_id);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301040 if (status != QDF_STATUS_SUCCESS)
1041 hdd_info("fail to flush mc list status %d", status);
1042 EXIT();
1043
1044 return;
1045
1046}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001047
1048/**
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001049 * hdd_update_conn_state_mask(): record info needed by wma_suspend_req
1050 * @adapter: adapter to get info from
1051 * @conn_state_mask: mask of connection info
1052 *
1053 * currently only need to send connection info.
1054 */
Jeff Johnsond6d1f632017-10-06 20:06:10 -07001055static void hdd_update_conn_state_mask(struct hdd_adapter *adapter,
1056 uint32_t *conn_state_mask)
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001057{
1058
1059 eConnectionState connState;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07001060 struct hdd_station_ctx *sta_ctx;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301061
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001062 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301063
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001064 connState = sta_ctx->conn_info.connState;
1065
1066 if (connState == eConnectionState_Associated ||
1067 connState == eConnectionState_IbssConnected)
Jeff Johnson1b780e42017-10-31 14:11:45 -07001068 *conn_state_mask |= (1 << adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001069}
1070
1071/**
1072 * hdd_suspend_wlan() - Driver suspend function
1073 * @callback: Callback function to invoke when driver is ready to suspend
1074 * @callbackContext: Context to pass back to @callback function
1075 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301076 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001077 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301078static int
1079hdd_suspend_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001080{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001081 struct hdd_context *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301082 QDF_STATUS status;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001083 struct hdd_adapter *adapter = NULL;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001084 uint32_t conn_state_mask = 0;
Jeff Johnson4f7f7c62017-10-05 08:53:41 -07001085
Jeff Johnsonc3273322016-07-06 15:28:17 -07001086 hdd_info("WLAN being suspended by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001087
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001088 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1089 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001090 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301091 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001092 }
1093
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301094 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001095 hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001096 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301097 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098 }
1099
Dustin Brown920397d2017-12-13 16:27:50 -08001100 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson1b780e42017-10-31 14:11:45 -07001101 if (wlan_hdd_validate_session_id(adapter->session_id)) {
1102 hdd_err("invalid session id: %d", adapter->session_id);
Dustin Brown920397d2017-12-13 16:27:50 -08001103 continue;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301104 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105
1106 /* stop all TX queues before suspend */
Srinivas Girigowda6598eea2017-07-06 19:26:19 -07001107 hdd_info("Disabling queues");
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001108 wlan_hdd_netif_queue_control(adapter,
Himanshu Agarwal865201d2017-04-12 15:45:31 +05301109 WLAN_STOP_ALL_NETIF_QUEUE,
1110 WLAN_CONTROL_PATH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001111
Hanumanth Reddy Pothula3def8942017-10-05 16:19:36 +05301112 if (adapter->device_mode == QDF_STA_MODE)
1113 status = hdd_enable_default_pkt_filters(adapter);
1114
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001115 /* Configure supported OffLoads */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001116 hdd_enable_host_offloads(adapter, pmo_apps_suspend);
1117 hdd_update_conn_state_mask(adapter, &conn_state_mask);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118 }
1119
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001120 status = pmo_ucfg_psoc_user_space_suspend_req(hdd_ctx->hdd_psoc,
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301121 QDF_SYSTEM_SUSPEND);
1122 if (status != QDF_STATUS_SUCCESS)
1123 return -EAGAIN;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001124
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001125 hdd_ctx->hdd_wlan_suspended = true;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301126 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001127
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301128 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001129}
1130
1131/**
1132 * hdd_resume_wlan() - Driver resume function
1133 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301134 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001135 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301136static int hdd_resume_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001137{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001138 struct hdd_context *hdd_ctx;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001139 struct hdd_adapter *adapter = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301140 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001141
Dustin Brown2d228232016-09-22 15:06:19 -07001142 hdd_info("WLAN being resumed by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001143
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001144 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1145 if (!hdd_ctx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001146 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301147 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001148 }
1149
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301150 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001151 hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001152 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301153 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001154 }
1155
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001156 hdd_ctx->hdd_wlan_suspended = false;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301157 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001158
1159 /*loop through all adapters. Concurrency */
Dustin Brown920397d2017-12-13 16:27:50 -08001160 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson1b780e42017-10-31 14:11:45 -07001161 if (wlan_hdd_validate_session_id(adapter->session_id)) {
1162 hdd_err("invalid session id: %d", adapter->session_id);
Dustin Brown920397d2017-12-13 16:27:50 -08001163 continue;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301164 }
1165 /* Disable supported OffLoads */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001166 hdd_disable_host_offloads(adapter, pmo_apps_resume);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001167
1168 /* wake the tx queues */
Dustin Brown2d228232016-09-22 15:06:19 -07001169 hdd_info("Enabling queues");
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001170 wlan_hdd_netif_queue_control(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001171 WLAN_WAKE_ALL_NETIF_QUEUE,
1172 WLAN_CONTROL_PATH);
1173
Hanumanth Reddy Pothula3def8942017-10-05 16:19:36 +05301174 if (adapter->device_mode == QDF_STA_MODE)
1175 status = hdd_disable_default_pkt_filters(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001176 }
Dustin Brown920397d2017-12-13 16:27:50 -08001177
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001178 hdd_ipa_resume(hdd_ctx);
1179 status = pmo_ucfg_psoc_user_space_resume_req(hdd_ctx->hdd_psoc,
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301180 QDF_SYSTEM_SUSPEND);
1181 if (status != QDF_STATUS_SUCCESS)
1182 return -EAGAIN;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001183
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301184 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001185}
1186
1187/**
Komal Seelam78ff65a2016-08-18 15:25:24 +05301188 * hdd_svc_fw_shutdown_ind() - API to send FW SHUTDOWN IND to Userspace
1189 *
1190 * @dev: Device Pointer
1191 *
1192 * Return: None
1193 */
1194void hdd_svc_fw_shutdown_ind(struct device *dev)
1195{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001196 struct hdd_context *hdd_ctx;
Komal Seelam78ff65a2016-08-18 15:25:24 +05301197
1198 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1199
1200 hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
1201 WLAN_SVC_FW_SHUTDOWN_IND,
1202 NULL, 0) : 0;
1203}
1204
1205/**
Arun Khandavallicc544b32017-01-30 19:52:16 +05301206 * hdd_ssr_restart_sap() - restart sap on SSR
1207 * @hdd_ctx: hdd context
1208 *
1209 * Return: nothing
1210 */
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001211static void hdd_ssr_restart_sap(struct hdd_context *hdd_ctx)
Arun Khandavallicc544b32017-01-30 19:52:16 +05301212{
Jeff Johnson75b737d2017-08-29 14:24:41 -07001213 struct hdd_adapter *adapter;
Arun Khandavallicc544b32017-01-30 19:52:16 +05301214
1215 ENTER();
1216
Dustin Brown920397d2017-12-13 16:27:50 -08001217 hdd_for_each_adapter(hdd_ctx, adapter) {
1218 if (adapter->device_mode == QDF_SAP_MODE) {
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001219 if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001220 hdd_debug("Restart prev SAP session");
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001221 wlan_hdd_start_sap(adapter, true);
1222 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05301223 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05301224 }
1225
1226 EXIT();
1227}
1228
1229/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001230 * hdd_wlan_shutdown() - HDD SSR shutdown function
1231 *
1232 * This function is called by the HIF to shutdown the driver during SSR.
1233 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301234 * Return: QDF_STATUS_SUCCESS if the driver was shut down,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001235 * or an error status otherwise
1236 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301237QDF_STATUS hdd_wlan_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001238{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001239 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001240 p_cds_sched_context cds_sched_context = NULL;
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001241 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001242
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001243 hdd_info("WLAN driver shutting down!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001244
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001245 /* Get the HDD context. */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001246 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1247 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001248 hdd_err("HDD context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301249 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001250 }
1251
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001252 policy_mgr_clear_concurrent_session_count(hdd_ctx->hdd_psoc);
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301253
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001254 hdd_debug("Invoking packetdump deregistration API");
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301255 wlan_deregister_txrx_packetdump();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001256 hdd_reset_all_adapters(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001257
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301258 /* Flush cached rx frame queue */
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001259 if (soc)
1260 cdp_flush_cache_rx_queue(soc);
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301261
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301262 /* De-register the HDD callbacks */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001263 hdd_deregister_cb(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001264
1265 cds_sched_context = get_cds_sched_ctxt();
1266
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001267 if (hdd_ctx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001268 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001269 hdd_ctx->is_scheduler_suspended = false;
Jeff Johnson214671b2017-10-30 19:45:23 -07001270 hdd_ctx->is_wiphy_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001271 }
1272#ifdef QCA_CONFIG_SMP
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001273 if (true == hdd_ctx->is_ol_rx_thread_suspended) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001274 complete(&cds_sched_context->ol_resume_rx_event);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001275 hdd_ctx->is_ol_rx_thread_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001276 }
1277#endif
1278
Manikandan Mohan71844ea2017-07-05 21:51:08 -07001279 hdd_ipa_uc_ssr_deinit();
Nitesh Shah61c10d92016-10-19 19:29:15 +05301280
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001281 hdd_bus_bandwidth_destroy(hdd_ctx);
Prashanth Bhattaab004382016-10-11 16:08:11 -07001282
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001283 hdd_wlan_stop_modules(hdd_ctx, false);
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301284
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001285 hdd_lpass_notify_stop(hdd_ctx);
Yuanyuan Liu3e918e52016-08-17 15:41:35 -07001286
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001287 wlan_objmgr_print_ref_all_objects_per_psoc(hdd_ctx->hdd_psoc);
Yue Ma2be12872017-06-02 13:06:58 -07001288
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001289 hdd_info("WLAN driver shutdown complete");
Yue Ma2be12872017-06-02 13:06:58 -07001290
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301291 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001292}
1293
Sen, Devendra154b3c42017-02-13 20:44:15 +05301294#ifdef FEATURE_WLAN_DIAG_SUPPORT
1295/**
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301296 * hdd_wlan_ssr_reinit_event()- send ssr reinit state
1297 *
1298 * This Function send send ssr reinit state diag event
1299 *
1300 * Return: void.
1301 */
Sen, Devendra154b3c42017-02-13 20:44:15 +05301302static void hdd_wlan_ssr_reinit_event(void)
1303{
1304 WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit);
1305 qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit));
1306 ssr_reinit.status = SSR_SUB_SYSTEM_REINIT;
1307 WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit,
1308 EVENT_WLAN_SSR_REINIT_SUBSYSTEM);
1309}
1310#else
1311static inline void hdd_wlan_ssr_reinit_event(void)
1312{
1313
1314}
1315#endif
1316
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001317/**
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301318 * hdd_send_default_scan_ies - send default scan ies to fw
1319 *
1320 * This function is used to send default scan ies to fw
1321 * in case of wlan re-init
1322 *
1323 * Return: void
1324 */
1325static void hdd_send_default_scan_ies(struct hdd_context *hdd_ctx)
1326{
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301327 struct hdd_adapter *adapter;
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301328
Dustin Brown920397d2017-12-13 16:27:50 -08001329 hdd_for_each_adapter(hdd_ctx, adapter) {
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301330 if (hdd_is_interface_up(adapter) &&
1331 (adapter->device_mode == QDF_STA_MODE ||
Hanumanth Reddy Pothula53dec122017-12-12 17:08:18 +05301332 adapter->device_mode == QDF_P2P_DEVICE_MODE) &&
1333 adapter->scan_info.default_scan_ies) {
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301334 sme_set_default_scan_ie(hdd_ctx->hHal,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001335 adapter->session_id,
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301336 adapter->scan_info.default_scan_ies,
1337 adapter->scan_info.default_scan_ies_len);
1338 }
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301339 }
1340}
1341
1342/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001343 * hdd_wlan_re_init() - HDD SSR re-init function
1344 *
1345 * This function is called by the HIF to re-initialize the driver after SSR.
1346 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301347 * Return: QDF_STATUS_SUCCESS if the driver was re-initialized,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001348 * or an error status otherwise
1349 */
Arun Khandavallifae92942016-08-01 13:31:08 +05301350QDF_STATUS hdd_wlan_re_init(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001351{
Arun Khandavallifae92942016-08-01 13:31:08 +05301352
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001353 struct hdd_context *hdd_ctx = NULL;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001354 struct hdd_adapter *adapter;
Arun Khandavallifae92942016-08-01 13:31:08 +05301355 int ret;
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301356 bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001357
1358 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1359
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001360 /* Get the HDD context */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001361 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1362 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001363 hdd_err("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001364 goto err_re_init;
1365 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001366 bug_on_reinit_failure = hdd_ctx->config->bug_on_reinit_failure;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001367
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001368 /* The driver should always be initialized in STA mode after SSR */
1369 hdd_set_conparam(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001370 /* Try to get an adapter from mode ID */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001371 adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE);
1372 if (!adapter) {
1373 adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
1374 if (!adapter) {
1375 adapter = hdd_get_adapter(hdd_ctx, QDF_IBSS_MODE);
1376 if (!adapter) {
1377 adapter = hdd_get_adapter(hdd_ctx,
1378 QDF_MONITOR_MODE);
1379 if (!adapter)
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001380 hdd_err("Failed to get Adapter!");
Arunk Khandavalli062fb032017-10-04 12:18:15 +05301381 }
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301382
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001383 }
1384 }
1385
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001386 if (hdd_ctx->config->enable_dp_trace)
1387 hdd_dp_trace_init(hdd_ctx->config);
Nirav Shahcc1f1ae2016-04-26 11:41:29 +05301388
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001389 hdd_bus_bandwidth_init(hdd_ctx);
Prashanth Bhattaab004382016-10-11 16:08:11 -07001390
Arun Khandavallicc544b32017-01-30 19:52:16 +05301391
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001392 ret = hdd_wlan_start_modules(hdd_ctx, adapter, true);
Arun Khandavallifae92942016-08-01 13:31:08 +05301393 if (ret) {
1394 hdd_err("Failed to start wlan after error");
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301395 goto err_re_init;
Arun Khandavallifae92942016-08-01 13:31:08 +05301396 }
1397
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001398 hdd_wlan_get_version(hdd_ctx, NULL, NULL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001399
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001400 wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
Wu Gao36717432016-11-21 15:09:48 +08001401 WLAN_SVC_FW_CRASHED_IND, NULL, 0);
1402
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001403 /* Restart all adapters */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001404 hdd_start_all_adapters(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001405
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001406 hdd_ctx->last_scan_reject_session_id = 0xFF;
1407 hdd_ctx->last_scan_reject_reason = 0;
1408 hdd_ctx->last_scan_reject_timestamp = 0;
1409 hdd_ctx->scan_reject_cnt = 0;
Sreelakshmi Konamkib53c6292017-03-01 13:13:23 +05301410
Selvaraj, Sridhar1c487562017-04-19 14:29:07 +05301411 hdd_set_roaming_in_progress(false);
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001412 complete(&adapter->roaming_comp_var);
Jeff Johnson59b19312017-11-02 21:14:33 -07001413 hdd_ctx->bt_coex_mode_set = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001414
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001415 /* Allow the phone to go to sleep */
1416 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05301417 /* set chip power save failure detected callback */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001418 sme_set_chip_pwr_save_fail_cb(hdd_ctx->hHal,
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05301419 hdd_chip_pwr_save_fail_detected_cb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001420
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001421 ret = hdd_register_cb(hdd_ctx);
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301422 if (ret) {
1423 hdd_err("Failed to register HDD callbacks!");
Chandrasekaran Manishekarcde33d72016-04-14 19:03:39 +05301424 goto err_cds_disable;
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301425 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001426
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001427 hdd_lpass_notify_start(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001428
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301429 hdd_send_default_scan_ies(hdd_ctx);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001430 hdd_info("WLAN host driver reinitiation completed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001431 goto success;
1432
1433err_cds_disable:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001434 hdd_wlan_stop_modules(hdd_ctx, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001435
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001436err_re_init:
1437 /* Allow the phone to go to sleep */
1438 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301439 if (bug_on_reinit_failure)
1440 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001441 return -EPERM;
1442
1443success:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001444 if (hdd_ctx->config->sap_internal_restart)
1445 hdd_ssr_restart_sap(hdd_ctx);
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301446
Sen, Devendra154b3c42017-02-13 20:44:15 +05301447 hdd_wlan_ssr_reinit_event();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301448 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001449}
1450
Jeff Johnson75b737d2017-08-29 14:24:41 -07001451int wlan_hdd_set_powersave(struct hdd_adapter *adapter,
Dustin Brownf660fb42016-09-09 12:04:00 -07001452 bool allow_power_save, uint32_t timeout)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453{
1454 tHalHandle hal;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001455 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001456
1457 if (NULL == adapter) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001458 hdd_err("Adapter NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001459 return -ENODEV;
1460 }
1461
1462 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1463 if (!hdd_ctx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001464 hdd_err("hdd context is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001465 return -EINVAL;
1466 }
1467
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001468 hdd_debug("Allow power save: %d", allow_power_save);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001469 hal = WLAN_HDD_GET_HAL_CTX(adapter);
1470
Dustin Brown84411b02017-07-21 16:44:44 -07001471 /*
1472 * This is a workaround for defective AP's that send a disassoc
1473 * immediately after WPS connection completes. Defer powersave by a
1474 * small amount if the affected AP is detected.
1475 */
1476 if (allow_power_save &&
1477 adapter->device_mode == QDF_STA_MODE &&
Jeff Johnsonb9424862017-10-30 08:49:35 -07001478 !adapter->session.station.ap_supports_immediate_power_save) {
Dustin Brown84411b02017-07-21 16:44:44 -07001479 timeout = AUTO_PS_DEFER_TIMEOUT_MS;
1480 hdd_debug("Defer power-save due to AP spec non-conformance");
Krunal Soni364e0872017-05-10 21:24:34 -07001481 }
1482
Dustin Brownf660fb42016-09-09 12:04:00 -07001483 if (allow_power_save) {
1484 if (QDF_STA_MODE == adapter->device_mode ||
1485 QDF_P2P_CLIENT_MODE == adapter->device_mode) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001486 hdd_debug("Disabling Auto Power save timer");
Dustin Brownf660fb42016-09-09 12:04:00 -07001487 sme_ps_disable_auto_ps_timer(
1488 WLAN_HDD_GET_HAL_CTX(adapter),
Jeff Johnson1b780e42017-10-31 14:11:45 -07001489 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001490 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001491
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001492 if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001493 hdd_debug("Wlan driver Entering Power save");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001494
1495 /*
1496 * Enter Power Save command received from GUI
1497 * this means DHCP is completed
1498 */
Yeshwanth Sriram Guntukaae03c432017-11-12 13:31:02 +05301499 if (timeout)
1500 sme_ps_enable_auto_ps_timer(hal,
1501 adapter->session_id,
1502 timeout);
1503 else
1504 sme_ps_enable_disable(hal, adapter->session_id,
1505 SME_PS_ENABLE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001506 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001507 hdd_debug("Power Save is not enabled in the cfg");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001508 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001509 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001510 hdd_debug("Wlan driver Entering Full Power");
Dustin Brownf660fb42016-09-09 12:04:00 -07001511
1512 /*
1513 * Enter Full power command received from GUI
1514 * this means we are disconnected
1515 */
1516 sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
Jeff Johnson1b780e42017-10-31 14:11:45 -07001517 adapter->session_id);
1518 sme_ps_enable_disable(hal, adapter->session_id, SME_PS_DISABLE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001519 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001520
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001521 return 0;
1522}
1523
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001524static void wlan_hdd_print_suspend_fail_stats(struct hdd_context *hdd_ctx)
Dustin Brown105d7902016-10-03 16:27:59 -07001525{
Dustin Brownd9322482017-01-09 12:46:03 -08001526 struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301527
Dustin Brown105d7902016-10-03 16:27:59 -07001528 hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d",
Dustin Brownd9322482017-01-09 12:46:03 -08001529 stats->suspend_fail[SUSPEND_FAIL_IPA],
1530 stats->suspend_fail[SUSPEND_FAIL_RADAR],
1531 stats->suspend_fail[SUSPEND_FAIL_ROAM],
1532 stats->suspend_fail[SUSPEND_FAIL_SCAN],
1533 stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]);
Dustin Brown105d7902016-10-03 16:27:59 -07001534}
1535
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001536void wlan_hdd_inc_suspend_stats(struct hdd_context *hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001537 enum suspend_fail_reason reason)
1538{
1539 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001540 hdd_ctx->suspend_resume_stats.suspend_fail[reason]++;
Dustin Brown105d7902016-10-03 16:27:59 -07001541 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
1542}
1543
Dustin Brown5fbb1052017-08-11 17:25:51 -07001544#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
1545static inline void
1546hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
1547{
1548 cfg80211_sched_scan_results(wiphy);
1549}
1550#else
1551static inline void
1552hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
1553{
1554 cfg80211_sched_scan_results(wiphy, reqid);
1555}
1556#endif
1557
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001558/**
1559 * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1560 * @wiphy: Pointer to wiphy
1561 *
1562 * This API is called when cfg80211 driver resumes driver updates
1563 * latest sched_scan scan result(if any) to cfg80211 database
1564 *
1565 * Return: integer status
1566 */
1567static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1568{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001569 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301570 QDF_STATUS status = QDF_STATUS_SUCCESS;
Dustin Brownd9322482017-01-09 12:46:03 -08001571 int exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001572 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1573
1574 ENTER();
1575
Dustin Brownd9322482017-01-09 12:46:03 -08001576 if (cds_is_driver_recovering()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001577 hdd_debug("Driver is recovering; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001578 exit_code = 0;
1579 goto exit_with_code;
1580 }
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001581
Anurag Chouhan6d760662016-02-20 16:05:43 +05301582 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001583 hdd_err("Command not allowed in FTM mode");
Dustin Brownd9322482017-01-09 12:46:03 -08001584 exit_code = -EINVAL;
1585 goto exit_with_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001586 }
1587
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001588 exit_code = wlan_hdd_validate_context(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001589 if (exit_code) {
1590 hdd_err("Invalid HDD context");
1591 goto exit_with_code;
1592 }
Arun Khandavallifae92942016-08-01 13:31:08 +05301593
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001594 mutex_lock(&hdd_ctx->iface_change_lock);
1595 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1596 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001597 hdd_debug("Driver is not enabled; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001598 exit_code = 0;
1599 goto exit_with_code;
Arun Khandavallifae92942016-08-01 13:31:08 +05301600 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001601 mutex_unlock(&hdd_ctx->iface_change_lock);
Dustin Brownd9322482017-01-09 12:46:03 -08001602
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001603 pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_MEDIUM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001604
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301605 status = hdd_resume_wlan();
1606 if (status != QDF_STATUS_SUCCESS) {
1607 exit_code = 0;
1608 goto exit_with_code;
1609 }
Rajeev Kumareada0d02016-12-08 17:44:17 -08001610 /* Resume control path scheduler */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001611 if (hdd_ctx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001612 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001613 hdd_ctx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001614 }
1615#ifdef QCA_CONFIG_SMP
1616 /* Resume tlshim Rx thread */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001617 if (hdd_ctx->is_ol_rx_thread_suspended) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001618 complete(&cds_sched_context->ol_resume_rx_event);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001619 hdd_ctx->is_ol_rx_thread_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001620 }
1621#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001622
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301623 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301624 TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
Jeff Johnson214671b2017-10-30 19:45:23 -07001625 NO_SESSION, hdd_ctx->is_wiphy_suspended));
Jeff Johnson214671b2017-10-30 19:45:23 -07001626 hdd_ctx->is_wiphy_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001627
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001628 hdd_ctx->suspend_resume_stats.resumes++;
Dustin Brownd9322482017-01-09 12:46:03 -08001629 exit_code = 0;
1630
1631exit_with_code:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301632 EXIT();
Dustin Brownd9322482017-01-09 12:46:03 -08001633 return exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001634}
1635
1636/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001637 * wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1638 * @wiphy: Pointer to wiphy
1639 *
1640 * This API is called when cfg80211 driver resumes driver updates
1641 * latest sched_scan scan result(if any) to cfg80211 database
1642 *
1643 * Return: integer status
1644 */
1645int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1646{
1647 int ret;
1648
1649 cds_ssr_protect(__func__);
1650 ret = __wlan_hdd_cfg80211_resume_wlan(wiphy);
1651 cds_ssr_unprotect(__func__);
1652
1653 return ret;
1654}
1655
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001656static void hdd_suspend_cb(void)
1657{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001658 struct hdd_context *hdd_ctx;
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001659
1660 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1661 if (!hdd_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001662 hdd_err("HDD context is NULL");
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001663 return;
1664 }
1665
1666 complete(&hdd_ctx->mc_sus_event_var);
1667}
1668
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001669/**
1670 * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1671 * @wiphy: Pointer to wiphy
1672 * @wow: Pointer to wow
1673 *
1674 * This API is called when cfg80211 driver suspends
1675 *
1676 * Return: integer status
1677 */
1678static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1679 struct cfg80211_wowlan *wow)
1680{
1681#ifdef QCA_CONFIG_SMP
1682#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */
1683#endif
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001684 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001685 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001686 struct hdd_adapter *adapter;
Jeff Johnson5287de52017-10-28 12:23:06 -07001687 struct hdd_scan_info *scan_info;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688 int rc;
1689
1690 ENTER();
1691
Anurag Chouhan6d760662016-02-20 16:05:43 +05301692 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001693 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001694 return -EINVAL;
1695 }
1696
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001697 rc = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301698 if (0 != rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001699 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001700
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001701 mutex_lock(&hdd_ctx->iface_change_lock);
1702 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1703 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001704 hdd_debug("Driver Modules not Enabled ");
Arun Khandavallifae92942016-08-01 13:31:08 +05301705 return 0;
1706 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001707 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavallifae92942016-08-01 13:31:08 +05301708
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709 /* If RADAR detection is in progress (HDD), prevent suspend. The flag
1710 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true
1711 * until CAC is done for a SoftAP which is in started state.
1712 */
Dustin Brown920397d2017-12-13 16:27:50 -08001713 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson1b780e42017-10-31 14:11:45 -07001714 if (wlan_hdd_validate_session_id(adapter->session_id)) {
1715 hdd_err("invalid session id: %d", adapter->session_id);
Dustin Brown920397d2017-12-13 16:27:50 -08001716 continue;
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301717 }
1718
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001719 if (QDF_SAP_MODE == adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001720 if (BSS_START ==
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07001721 WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter)->bss_state &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722 true ==
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001723 WLAN_HDD_GET_AP_CTX_PTR(adapter)->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001724 dfs_cac_block_tx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001725 hdd_err("RADAR detection in progress, do not allow suspend");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001726 wlan_hdd_inc_suspend_stats(hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001727 SUSPEND_FAIL_RADAR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001728 return -EAGAIN;
Jeff Johnson60cbd2d2017-11-03 18:26:28 -07001729 } else if (!hdd_ctx->config->enable_sap_suspend) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730 /* return -EOPNOTSUPP if SAP does not support
1731 * suspend
1732 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001733 hdd_err("SAP does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734 return -EOPNOTSUPP;
1735 }
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001736 } else if (QDF_P2P_GO_MODE == adapter->device_mode) {
Jeff Johnson60cbd2d2017-11-03 18:26:28 -07001737 if (!hdd_ctx->config->enable_sap_suspend) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001738 /* return -EOPNOTSUPP if GO does not support
1739 * suspend
1740 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001741 hdd_err("GO does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742 return -EOPNOTSUPP;
1743 }
1744 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001745 }
1746
1747 /* Stop ongoing scan on each interface */
Dustin Brown920397d2017-12-13 16:27:50 -08001748 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson5287de52017-10-28 12:23:06 -07001749 scan_info = &adapter->scan_info;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001750
Sandeep Puligillaf8527122016-11-16 18:35:16 -08001751 if (sme_neighbor_middle_of_roaming
Jeff Johnson1b780e42017-10-31 14:11:45 -07001752 (hdd_ctx->hHal, adapter->session_id)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001753 hdd_err("Roaming in progress, do not allow suspend");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001754 wlan_hdd_inc_suspend_stats(hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001755 SUSPEND_FAIL_ROAM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001756 return -EAGAIN;
1757 }
1758
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001759 wlan_abort_scan(hdd_ctx->hdd_pdev, INVAL_PDEV_ID,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001760 adapter->session_id, INVALID_SCAN_ID, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001761 }
1762
Dustin Brown84411b02017-07-21 16:44:44 -07001763 /* flush any pending powersave timers */
Dustin Brown920397d2017-12-13 16:27:50 -08001764 hdd_for_each_adapter(hdd_ctx, adapter)
Jeff Johnson1b780e42017-10-31 14:11:45 -07001765 sme_ps_timer_flush_sync(hdd_ctx->hHal, adapter->session_id);
Dustin Brown84411b02017-07-21 16:44:44 -07001766
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001767 /*
1768 * Suspend IPA early before proceeding to suspend other entities like
1769 * firmware to avoid any race conditions.
1770 */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001771 if (hdd_ipa_suspend(hdd_ctx)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001772 hdd_err("IPA not ready to suspend!");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001773 wlan_hdd_inc_suspend_stats(hdd_ctx, SUSPEND_FAIL_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001774 return -EAGAIN;
1775 }
1776
Rajeev Kumareada0d02016-12-08 17:44:17 -08001777 /* Suspend control path scheduler */
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001778 scheduler_register_hdd_suspend_callback(hdd_suspend_cb);
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301779 scheduler_set_event_mask(MC_SUSPEND_EVENT);
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001780 scheduler_wake_up_controller_thread();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001781
Rajeev Kumareada0d02016-12-08 17:44:17 -08001782 /* Wait for suspend confirmation from scheduler */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001783 rc = wait_for_completion_timeout(&hdd_ctx->mc_sus_event_var,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784 msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
1785 if (!rc) {
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301786 scheduler_clear_event_mask(MC_SUSPEND_EVENT);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001787 hdd_err("Failed to stop mc thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001788 goto resume_tx;
1789 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001790 hdd_ctx->is_scheduler_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001791
1792#ifdef QCA_CONFIG_SMP
1793 /* Suspend tlshim rx thread */
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301794 set_bit(RX_SUSPEND_EVENT, &cds_sched_context->ol_rx_event_flag);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001795 wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue);
1796 rc = wait_for_completion_timeout(&cds_sched_context->
1797 ol_suspend_rx_event,
1798 msecs_to_jiffies
1799 (RX_TLSHIM_SUSPEND_TIMEOUT));
1800 if (!rc) {
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301801 clear_bit(RX_SUSPEND_EVENT,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001802 &cds_sched_context->ol_rx_event_flag);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001803 hdd_err("Failed to stop tl_shim rx thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001804 goto resume_all;
1805 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001806 hdd_ctx->is_ol_rx_thread_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001807#endif
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301808 if (hdd_suspend_wlan() < 0)
1809 goto resume_all;
1810
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301811 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301812 TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
Jeff Johnson214671b2017-10-30 19:45:23 -07001813 NO_SESSION, hdd_ctx->is_wiphy_suspended));
1814 hdd_ctx->is_wiphy_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001815
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001816 pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_NONE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001817
1818 EXIT();
1819 return 0;
1820
1821#ifdef QCA_CONFIG_SMP
1822resume_all:
1823
Rajeev Kumar0b732952016-12-08 17:51:39 -08001824 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001825 hdd_ctx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001826#endif
1827
1828resume_tx:
1829
1830 hdd_resume_wlan();
1831 return -ETIME;
1832
1833}
1834
1835/**
1836 * wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1837 * @wiphy: Pointer to wiphy
1838 * @wow: Pointer to wow
1839 *
1840 * This API is called when cfg80211 driver suspends
1841 *
1842 * Return: integer status
1843 */
1844int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1845 struct cfg80211_wowlan *wow)
1846{
1847 int ret;
1848
1849 cds_ssr_protect(__func__);
1850 ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
1851 cds_ssr_unprotect(__func__);
1852
1853 return ret;
1854}
1855
1856/**
Komal Seelama89be8d2016-09-29 11:09:26 +05301857 * hdd_stop_dhcp_ind() - API to stop DHCP sequence
1858 * @adapter: Adapter on which DHCP needs to be stopped
1859 *
1860 * Release the wakelock held for DHCP process and allow
1861 * the runtime pm to continue
1862 *
1863 * Return: None
1864 */
Jeff Johnson75b737d2017-08-29 14:24:41 -07001865static void hdd_stop_dhcp_ind(struct hdd_adapter *adapter)
Komal Seelama89be8d2016-09-29 11:09:26 +05301866{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001867 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Komal Seelama89be8d2016-09-29 11:09:26 +05301868
Srinivas Girigowdac06543c2017-03-09 15:10:03 -08001869 hdd_debug("DHCP stop indicated through power save");
Komal Seelama89be8d2016-09-29 11:09:26 +05301870 sme_dhcp_stop_ind(hdd_ctx->hHal, adapter->device_mode,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001871 adapter->mac_addr.bytes,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001872 adapter->session_id);
Komal Seelama89be8d2016-09-29 11:09:26 +05301873 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
Jingxiang Geb49aa302018-01-17 20:54:15 +08001874 qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect);
Komal Seelama89be8d2016-09-29 11:09:26 +05301875}
1876
1877/**
1878 * hdd_start_dhcp_ind() - API to start DHCP sequence
1879 * @adapter: Adapter on which DHCP needs to be stopped
1880 *
1881 * Prevent APPS suspend and the runtime suspend during
1882 * DHCP sequence
1883 *
1884 * Return: None
1885 */
Jeff Johnson75b737d2017-08-29 14:24:41 -07001886static void hdd_start_dhcp_ind(struct hdd_adapter *adapter)
Komal Seelama89be8d2016-09-29 11:09:26 +05301887{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001888 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Komal Seelama89be8d2016-09-29 11:09:26 +05301889
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001890 hdd_debug("DHCP start indicated through power save");
Jingxiang Geb49aa302018-01-17 20:54:15 +08001891 qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.connect);
Dustin Brownceed67e2017-05-26 11:57:31 -07001892 hdd_prevent_suspend_timeout(HDD_WAKELOCK_TIMEOUT_CONNECT,
1893 WIFI_POWER_EVENT_WAKELOCK_DHCP);
Komal Seelama89be8d2016-09-29 11:09:26 +05301894 sme_dhcp_start_ind(hdd_ctx->hHal, adapter->device_mode,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001895 adapter->mac_addr.bytes,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001896 adapter->session_id);
Komal Seelama89be8d2016-09-29 11:09:26 +05301897}
1898
1899/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900 * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
1901 * @wiphy: Pointer to wiphy
1902 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07001903 * @allow_power_save: is wlan allowed to go into power save mode
1904 * @timeout: Timeout value in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001905 *
1906 * Return: 0 for success, non-zero for failure
1907 */
1908static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07001909 struct net_device *dev,
1910 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911 int timeout)
1912{
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001913 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001914 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001915 int status;
1916
Dustin Brownecfce632016-09-13 10:41:45 -07001917 ENTER();
1918
Dustin Brownf660fb42016-09-09 12:04:00 -07001919 if (timeout < 0) {
Yeshwanth Sriram Guntukaae03c432017-11-12 13:31:02 +05301920 hdd_debug("User space timeout: %d; Enter full power or power save",
1921 timeout);
1922 timeout = 0;
Dustin Brownf660fb42016-09-09 12:04:00 -07001923 }
1924
Anurag Chouhan6d760662016-02-20 16:05:43 +05301925 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001926 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001927 return -EINVAL;
1928 }
1929
Jeff Johnson1b780e42017-10-31 14:11:45 -07001930 if (wlan_hdd_validate_session_id(adapter->session_id)) {
1931 hdd_err("invalid session id: %d", adapter->session_id);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301932 return -EINVAL;
1933 }
1934
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301935 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001936 TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001937 adapter->session_id, timeout));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001938
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001939 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001940 status = wlan_hdd_validate_context(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001941
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301942 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001943 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001944
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001945 mutex_lock(&hdd_ctx->iface_change_lock);
1946 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1947 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001948 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05301949 return 0;
1950 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001951 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavalli99286452016-08-22 12:13:41 +05301952
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001953 status = wlan_hdd_set_powersave(adapter, allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001955 allow_power_save ? hdd_stop_dhcp_ind(adapter) :
1956 hdd_start_dhcp_ind(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001957
1958 EXIT();
1959 return status;
1960}
1961
1962/**
1963 * wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
1964 * @wiphy: Pointer to wiphy
1965 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07001966 * @allow_power_save: is wlan allowed to go into power save mode
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001967 * @timeout: Timeout value
1968 *
1969 * Return: 0 for success, non-zero for failure
1970 */
1971int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07001972 struct net_device *dev,
1973 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001974 int timeout)
1975{
1976 int ret;
1977
1978 cds_ssr_protect(__func__);
Dustin Brownf660fb42016-09-09 12:04:00 -07001979 ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev,
1980 allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001981 cds_ssr_unprotect(__func__);
1982
1983 return ret;
1984}
1985
1986/**
1987 * __wlan_hdd_cfg80211_set_txpower() - set TX power
1988 * @wiphy: Pointer to wiphy
1989 * @wdev: Pointer to network device
1990 * @type: TX power setting type
1991 * @dbm: TX power in dbm
1992 *
1993 * Return: 0 for success, non-zero for failure
1994 */
1995static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001996 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001997 enum nl80211_tx_power_setting type,
1998 int dbm)
1999{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002000 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002001 tHalHandle hHal = NULL;
Dustin Brownce5b3d32018-01-17 15:07:38 -08002002 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
2003 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BCAST_INIT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002004 int status;
2005
2006 ENTER();
2007
Anurag Chouhan6d760662016-02-20 16:05:43 +05302008 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002009 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002010 return -EINVAL;
2011 }
2012
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302013 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002014 TRACE_CODE_HDD_CFG80211_SET_TXPOWER,
2015 NO_SESSION, type));
2016
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002017 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302018 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002019 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002020
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002021 hHal = hdd_ctx->hHal;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002022
2023 if (0 != sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, dbm)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002024 hdd_err("sme_cfg_set_int failed for tx power %hu",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002025 dbm);
2026 return -EIO;
2027 }
2028
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002029 hdd_debug("Set tx power level %d dbm", dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002030
2031 switch (type) {
2032 /* Automatically determine transmit power */
2033 case NL80211_TX_POWER_AUTOMATIC:
2034 /* Fall through */
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05302035 case NL80211_TX_POWER_LIMITED:
2036 /* Limit TX power by the mBm parameter */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037 if (sme_set_max_tx_power(hHal, bssid, selfMac, dbm) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302038 QDF_STATUS_SUCCESS) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002039 hdd_err("Setting maximum tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002040 return -EIO;
2041 }
2042 break;
2043
2044 case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */
Jeff Johnsonc3273322016-07-06 15:28:17 -07002045 hdd_err("NL80211_TX_POWER_FIXED not supported");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002046 return -EOPNOTSUPP;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002047
2048 default:
Jeff Johnsonc3273322016-07-06 15:28:17 -07002049 hdd_err("Invalid power setting type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002050 return -EIO;
2051 }
2052
2053 EXIT();
2054 return 0;
2055}
2056
2057/**
2058 * wlan_hdd_cfg80211_set_txpower() - set TX power
2059 * @wiphy: Pointer to wiphy
2060 * @wdev: Pointer to network device
2061 * @type: TX power setting type
2062 * @dbm: TX power in dbm
2063 *
2064 * Return: 0 for success, non-zero for failure
2065 */
2066int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002067 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068 enum nl80211_tx_power_setting type,
2069 int dbm)
2070{
2071 int ret;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05302072
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002073 cds_ssr_protect(__func__);
2074 ret = __wlan_hdd_cfg80211_set_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002075 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002076 type, dbm);
2077 cds_ssr_unprotect(__func__);
2078
2079 return ret;
2080}
2081
2082/**
2083 * __wlan_hdd_cfg80211_get_txpower() - get TX power
2084 * @wiphy: Pointer to wiphy
2085 * @wdev: Pointer to network device
2086 * @dbm: Pointer to TX power in dbm
2087 *
2088 * Return: 0 for success, non-zero for failure
2089 */
2090static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002091 struct wireless_dev *wdev,
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002092 int *dbm)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002093{
2094
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002095 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002096 struct net_device *ndev = wdev->netdev;
Jeff Johnson75b737d2017-08-29 14:24:41 -07002097 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002098 int status;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07002099 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002100
2101 ENTER();
2102
Anurag Chouhan6d760662016-02-20 16:05:43 +05302103 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002104 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002105 return -EINVAL;
2106 }
2107
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002108 status = wlan_hdd_validate_context(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002109 if (0 != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002110 *dbm = 0;
2111 return status;
2112 }
2113
Arun Khandavalli99286452016-08-22 12:13:41 +05302114 /* Validate adapter sessionId */
Jeff Johnson1b780e42017-10-31 14:11:45 -07002115 if (wlan_hdd_validate_session_id(adapter->session_id)) {
2116 hdd_err("invalid session id: %d", adapter->session_id);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002117 return -EINVAL;
Arun Khandavalli99286452016-08-22 12:13:41 +05302118 }
2119
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002120 mutex_lock(&hdd_ctx->iface_change_lock);
2121 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2122 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002123 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05302124 /* Send cached data to upperlayer*/
Jeff Johnson861dd4f2017-10-24 10:10:40 -07002125 *dbm = adapter->hdd_stats.class_a_stat.max_pwr;
Arun Khandavalli99286452016-08-22 12:13:41 +05302126 return 0;
2127 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002128 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavalli99286452016-08-22 12:13:41 +05302129
Ganesh Kondabattinif847f062017-05-26 12:36:24 +05302130 if (sta_ctx->conn_info.connState != eConnectionState_Associated) {
2131 hdd_debug("Not associated");
2132 /*To keep GUI happy */
2133 *dbm = 0;
2134 return 0;
2135 }
2136
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302137 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302138 TRACE_CODE_HDD_CFG80211_GET_TXPOWER,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002139 adapter->session_id, adapter->device_mode));
Arun Khandavalli99286452016-08-22 12:13:41 +05302140 wlan_hdd_get_class_astats(adapter);
Jeff Johnson861dd4f2017-10-24 10:10:40 -07002141 *dbm = adapter->hdd_stats.class_a_stat.max_pwr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002142
2143 EXIT();
2144 return 0;
2145}
2146
2147/**
2148 * wlan_hdd_cfg80211_get_txpower() - cfg80211 get power handler function
2149 * @wiphy: Pointer to wiphy structure.
2150 * @wdev: Pointer to wireless_dev structure.
2151 * @dbm: dbm
2152 *
2153 * This is the cfg80211 get txpower handler function which invokes
2154 * the internal function @__wlan_hdd_cfg80211_get_txpower with
2155 * SSR protection.
2156 *
2157 * Return: 0 for success, error number on failure.
2158 */
2159int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002160 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002161 int *dbm)
2162{
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002163 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002164
2165 cds_ssr_protect(__func__);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002166 ret = __wlan_hdd_cfg80211_get_txpower(wiphy, wdev, dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002167 cds_ssr_unprotect(__func__);
2168
2169 return ret;
2170}
Kapil Gupta6213c012016-09-02 19:39:09 +05302171
Jeff Johnson4fbee2f2017-10-03 11:19:35 -07002172int hdd_set_qpower_config(struct hdd_context *hddctx,
2173 struct hdd_adapter *adapter,
Dustin Brown10a7b712016-10-07 10:31:16 -07002174 u8 qpower)
Kapil Gupta6213c012016-09-02 19:39:09 +05302175{
Dustin Brown10a7b712016-10-07 10:31:16 -07002176 QDF_STATUS status;
Kapil Gupta6213c012016-09-02 19:39:09 +05302177
2178 if (!hddctx->config->enablePowersaveOffload) {
2179 hdd_err("qpower is disabled in configuration");
2180 return -EINVAL;
2181 }
Manjeet Singh91b7bb82017-02-10 18:35:40 +05302182 if (adapter->device_mode != QDF_STA_MODE &&
2183 adapter->device_mode != QDF_P2P_CLIENT_MODE) {
2184 hdd_info(FL("QPOWER only allowed in STA/P2P-Client modes:%d "),
2185 adapter->device_mode);
2186 return -EINVAL;
2187 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002188
Kapil Gupta6213c012016-09-02 19:39:09 +05302189 if (qpower > PS_DUTY_CYCLING_QPOWER ||
2190 qpower < PS_LEGACY_NODEEPSLEEP) {
Dustin Brown10a7b712016-10-07 10:31:16 -07002191 hdd_err("invalid qpower value: %d", qpower);
Kapil Gupta6213c012016-09-02 19:39:09 +05302192 return -EINVAL;
2193 }
Kapil Gupta6213c012016-09-02 19:39:09 +05302194
Kiran Kumar Lokere7006e0a2017-03-07 19:28:36 -08002195 if (hddctx->config->nMaxPsPoll) {
2196 if ((qpower == PS_QPOWER_NODEEPSLEEP) ||
2197 (qpower == PS_LEGACY_NODEEPSLEEP))
2198 qpower = PS_LEGACY_NODEEPSLEEP;
2199 else
2200 qpower = PS_LEGACY_DEEPSLEEP;
2201 hdd_info("Qpower disabled, %d", qpower);
2202 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07002203 status = wma_set_qpower_config(adapter->session_id, qpower);
Dustin Brown10a7b712016-10-07 10:31:16 -07002204 if (status != QDF_STATUS_SUCCESS) {
2205 hdd_err("failed to configure qpower: %d", status);
2206 return -EINVAL;
Kapil Gupta6213c012016-09-02 19:39:09 +05302207 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002208
Kapil Gupta6213c012016-09-02 19:39:09 +05302209 return 0;
2210}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002211
Dustin Brown54096432017-02-23 13:00:44 -08002212
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002213#ifdef WLAN_SUSPEND_RESUME_TEST
Dustin Brownbc81a472016-10-26 16:56:59 -07002214static struct net_device *g_dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002215static struct wiphy *g_wiphy;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002216static enum wow_resume_trigger g_resume_trigger;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002217
2218#define HDD_FA_SUSPENDED_BIT (0)
2219static unsigned long fake_apps_state;
2220
Dustin Brownd53d1a82016-10-03 12:57:33 -07002221/**
2222 * __hdd_wlan_fake_apps_resume() - The core logic for
2223 * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(),
2224 * which is only need for non-irq resume
Dustin Brownbc81a472016-10-26 16:56:59 -07002225 * @wiphy: the kernel wiphy struct for the device being resumed
2226 * @dev: the kernel net_device struct for the device being resumed
Dustin Brownd53d1a82016-10-03 12:57:33 -07002227 *
Dustin Brownbc81a472016-10-26 16:56:59 -07002228 * Return: none, calls QDF_BUG() on failure
Dustin Brownd53d1a82016-10-03 12:57:33 -07002229 */
Dustin Brownbc81a472016-10-26 16:56:59 -07002230static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy,
2231 struct net_device *dev)
Dustin Brownd53d1a82016-10-03 12:57:33 -07002232{
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002233 struct hif_opaque_softc *hif_ctx;
Dustin Brownddb59702017-01-12 16:20:31 -08002234 qdf_device_t qdf_dev;
Dustin Brownd53d1a82016-10-03 12:57:33 -07002235
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002236 hdd_info("Unit-test resume WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002237
2238 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2239 if (!qdf_dev) {
2240 hdd_err("Failed to get QDF device context");
2241 QDF_BUG(0);
2242 return;
2243 }
2244
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002245 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2246 if (!hif_ctx) {
2247 hdd_err("Failed to get HIF context");
2248 return;
2249 }
2250
Dustin Brownd53d1a82016-10-03 12:57:33 -07002251 if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002252 hdd_alert("Not unit-test suspended; Nothing to do");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002253 return;
2254 }
2255
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002256 /* simulate kernel disable irqs */
2257 QDF_BUG(!hif_apps_wake_irq_disable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002258
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002259 QDF_BUG(!wlan_hdd_bus_resume_noirq());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002260
2261 /* simulate kernel enable irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002262 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002263
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002264 QDF_BUG(!wlan_hdd_bus_resume());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002265
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002266 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
2267
2268 if (g_resume_trigger == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2269 hif_vote_link_down(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002270
2271 dev->watchdog_timeo = HDD_TX_TIMEOUT;
Dustin Brown562b9672016-12-22 15:25:33 -08002272
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002273 hdd_alert("Unit-test resume succeeded");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002274}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002275
2276/**
2277 * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming
2278 * from unit-test initiated suspend from irq wakeup signal
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002279 *
2280 * Resume wlan after getting very 1st CE interrupt from target
2281 *
2282 * Return: none
2283 */
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002284static void hdd_wlan_fake_apps_resume_irq_callback(void)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002285{
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002286 hdd_info("Trigger unit-test resume WLAN");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002287
2288 QDF_BUG(g_wiphy);
Dustin Brownbc81a472016-10-26 16:56:59 -07002289 QDF_BUG(g_dev);
2290 __hdd_wlan_fake_apps_resume(g_wiphy, g_dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002291 g_wiphy = NULL;
Dustin Brownbc81a472016-10-26 16:56:59 -07002292 g_dev = NULL;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002293}
2294
Dustin Brown54096432017-02-23 13:00:44 -08002295int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev,
2296 enum wow_interface_pause pause_setting,
2297 enum wow_resume_trigger resume_setting)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002298{
Dustin Brownddb59702017-01-12 16:20:31 -08002299 qdf_device_t qdf_dev;
2300 struct hif_opaque_softc *hif_ctx;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002301 int errno;
Dustin Brown54096432017-02-23 13:00:44 -08002302 struct wow_enable_params wow_params = {
2303 .is_unit_test = true,
2304 .interface_pause = pause_setting,
2305 .resume_trigger = resume_setting
2306 };
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002307
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002308 hdd_info("Unit-test suspend WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002309
Dustin Brown54096432017-02-23 13:00:44 -08002310 if (pause_setting < WOW_INTERFACE_PAUSE_DEFAULT ||
2311 pause_setting >= WOW_INTERFACE_PAUSE_COUNT) {
2312 hdd_err("Invalid interface pause %d (expected range [0, 2])",
2313 pause_setting);
2314 return -EINVAL;
2315 }
2316
2317 if (resume_setting < WOW_RESUME_TRIGGER_DEFAULT ||
2318 resume_setting >= WOW_RESUME_TRIGGER_COUNT) {
2319 hdd_err("Invalid resume trigger %d (expected range [0, 2])",
2320 resume_setting);
2321 return -EINVAL;
2322 }
2323
Dustin Brownddb59702017-01-12 16:20:31 -08002324 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2325 if (!qdf_dev) {
2326 hdd_err("Failed to get QDF device context");
2327 return -EINVAL;
2328 }
2329
2330 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2331 if (!hif_ctx) {
2332 hdd_err("Failed to get HIF context");
2333 return -EINVAL;
2334 }
2335
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002336 if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002337 hdd_alert("Already unit-test suspended; Nothing to do");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002338 return 0;
2339 }
2340
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002341 /* pci link is needed to wakeup from HTC wakeup trigger */
2342 if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2343 hif_vote_link_up(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002344
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002345 errno = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL);
2346 if (errno)
2347 goto link_down;
2348
2349 errno = wlan_hdd_unit_test_bus_suspend(wow_params);
2350 if (errno)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002351 goto cfg80211_resume;
2352
2353 /* simulate kernel disabling irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002354 errno = hif_apps_irqs_disable(hif_ctx);
2355 if (errno)
2356 goto bus_resume;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002357
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002358 errno = wlan_hdd_bus_suspend_noirq();
2359 if (errno)
2360 goto enable_irqs;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002361
Dustin Brownbc81a472016-10-26 16:56:59 -07002362 /* pass wiphy/dev to callback via global variables */
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002363 g_wiphy = wiphy;
Dustin Brownbc81a472016-10-26 16:56:59 -07002364 g_dev = dev;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002365 g_resume_trigger = resume_setting;
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002366 hif_ut_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002367
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002368 /* re-enable wake irq */
2369 errno = hif_apps_wake_irq_enable(hif_ctx);
2370 if (errno)
2371 goto fake_apps_resume;
2372
Dustin Brownbc81a472016-10-26 16:56:59 -07002373 /*
2374 * Tell the kernel not to worry if TX queues aren't moving. This is
2375 * expected since we are suspending the wifi hardware, but not APPS
2376 */
2377 dev->watchdog_timeo = INT_MAX;
2378
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002379 hdd_alert("Unit-test suspend succeeded");
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002380
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002381 return 0;
2382
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002383fake_apps_resume:
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002384 hif_ut_apps_resume(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002385
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002386enable_irqs:
2387 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
2388
2389bus_resume:
2390 QDF_BUG(!wlan_hdd_bus_resume());
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002391
2392cfg80211_resume:
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002393 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002394
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002395link_down:
2396 hif_vote_link_down(hif_ctx);
2397
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002398 clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state);
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002399 hdd_err("Unit-test suspend failed: %d", errno);
2400
2401 return errno;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002402}
2403
Dustin Brownbc81a472016-10-26 16:56:59 -07002404int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002405{
Dustin Brownddb59702017-01-12 16:20:31 -08002406 struct hif_opaque_softc *hif_ctx;
2407
2408 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2409 if (!hif_ctx) {
2410 hdd_err("Failed to get HIF context");
2411 return -EINVAL;
2412 }
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002413
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002414 hif_ut_apps_resume(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002415 __hdd_wlan_fake_apps_resume(wiphy, dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002416
2417 return 0;
2418}
2419#endif