blob: cf07dd3b67c7df2ab992ef67681e07a9cbf13405 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Poddar, Siddartha78cac32016-12-29 20:08:34 +05302 * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_power.c
30 *
31 * WLAN power management functions
32 *
33 */
34
35/* Include files */
36
37#include <linux/pm.h>
38#include <linux/wait.h>
39#include <linux/cpu.h>
40#include <wlan_hdd_includes.h>
41#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK)
42#include <linux/wakelock.h>
43#endif
Anurag Chouhan6d760662016-02-20 16:05:43 +053044#include "qdf_types.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080045#include "sme_api.h"
46#include <cds_api.h>
47#include <cds_sched.h>
48#include <mac_init_api.h>
49#include <wlan_qct_sys.h>
50#include <wlan_hdd_main.h>
51#include <wlan_hdd_assoc.h>
52#include <wlan_nlink_srv.h>
53#include <wlan_hdd_misc.h>
54#include <wlan_hdd_power.h>
Jeff Johnsonc8d0c252016-10-05 16:19:50 -070055#include <wlan_hdd_host_offload.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080056#include <dbglog_host.h>
57#include <wlan_hdd_trace.h>
Masti, Narayanraddi3e26de62016-08-19 14:33:22 +053058#include <wlan_hdd_p2p.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059
60#include <linux/semaphore.h>
61#include <wlan_hdd_hostapd.h>
62#include "cfg_api.h"
63
64#include <linux/inetdevice.h>
65#include <wlan_hdd_cfg.h>
Sandeep Puligillae390be52016-02-08 17:07:05 -080066#include <wlan_hdd_scan.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080067#include <wlan_hdd_cfg80211.h>
68#include <net/addrconf.h>
69#include <wlan_hdd_ipa.h>
Jeff Johnson2b0a7b82016-05-18 15:08:02 -070070#include <wlan_hdd_lpass.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071
72#include <wma_types.h>
Poddar, Siddartha78cac32016-12-29 20:08:34 +053073#include <ol_txrx_osif_api.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080074#include "hif.h"
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"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080085
86/* Preprocessor definitions and constants */
Yue Ma5fe30dd2017-05-02 15:47:40 -070087#ifdef QCA_WIFI_NAPIER_EMULATION
88#define HDD_SSR_BRING_UP_TIME 3000000
89#else
Yue Ma4ea4f052015-10-27 12:25:27 -070090#define HDD_SSR_BRING_UP_TIME 30000
Yue Ma5fe30dd2017-05-02 15:47:40 -070091#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080092
93/* Type declarations */
94
Abhishek Singhbaea27d2016-04-27 13:29:30 +053095#ifdef FEATURE_WLAN_DIAG_SUPPORT
96/**
97 * hdd_wlan_suspend_resume_event()- send suspend/resume state
98 * @state: suspend/resume state
99 *
100 * This Function send send suspend resume state diag event
101 *
102 * Return: void.
103 */
104void hdd_wlan_suspend_resume_event(uint8_t state)
105{
106 WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend);
107 qdf_mem_zero(&suspend_state, sizeof(suspend_state));
108
109 suspend_state.state = state;
110 WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
111}
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530112
113/**
114 * hdd_wlan_offload_event()- send offloads event
115 * @type: offload type
116 * @state: enabled or disabled
117 *
118 * This Function send offloads enable/disable diag event
119 *
120 * Return: void.
121 */
122
123void hdd_wlan_offload_event(uint8_t type, uint8_t state)
124{
125 WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req);
126 qdf_mem_zero(&host_offload, sizeof(host_offload));
127
128 host_offload.offload_type = type;
129 host_offload.state = state;
130
131 WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ);
132}
Abhishek Singhbaea27d2016-04-27 13:29:30 +0530133#endif
134
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800135/**
Mukul Sharma3d36c392017-01-18 18:39:12 +0530136 * hdd_enable_gtk_offload() - enable GTK offload
137 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800138 *
Mukul Sharma3d36c392017-01-18 18:39:12 +0530139 * Central function to enable GTK offload.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140 *
141 * Return: nothing
142 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700143static void hdd_enable_gtk_offload(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800144{
Mukul Sharma3d36c392017-01-18 18:39:12 +0530145 QDF_STATUS status;
Jeff Johnson4f7f7c62017-10-05 08:53:41 -0700146
Mukul Sharma3d36c392017-01-18 18:39:12 +0530147 status = pmo_ucfg_enable_gtk_offload_in_fwr(adapter->hdd_vdev);
148 if (status != QDF_STATUS_SUCCESS)
149 hdd_info("Failed to enable gtk offload");
150}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800151
Mukul Sharma3d36c392017-01-18 18:39:12 +0530152/**
153 * hdd_disable_gtk_offload() - disable GTK offload
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700154 * @adapter: pointer to the adapter
Mukul Sharma3d36c392017-01-18 18:39:12 +0530155 *
156 * Central function to disable GTK offload.
157 *
158 * Return: nothing
159 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700160static void hdd_disable_gtk_offload(struct hdd_adapter *adapter)
Mukul Sharma3d36c392017-01-18 18:39:12 +0530161{
162 struct pmo_gtk_rsp_req gtk_rsp_request;
163 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800164
Mukul Sharma3d36c392017-01-18 18:39:12 +0530165 /* ensure to get gtk rsp first before disable it*/
166 gtk_rsp_request.callback =
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530167 wlan_hdd_cfg80211_update_replay_counter_cb;
Mukul Sharma3d36c392017-01-18 18:39:12 +0530168 /* Passing as void* as PMO does not know legacy HDD adapter type */
169 gtk_rsp_request.callback_context =
170 (void *)adapter;
171 status = pmo_ucfg_get_gtk_rsp(adapter->hdd_vdev,
172 &gtk_rsp_request);
173 if (status != QDF_STATUS_SUCCESS) {
174 hdd_err("Failed to send get gtk rsp status:%d", status);
175 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800176 }
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800177 hdd_debug("send get_gtk_rsp successful");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530178 status = pmo_ucfg_disable_gtk_offload_in_fwr(adapter->hdd_vdev);
179 if (status != QDF_STATUS_SUCCESS)
180 hdd_info("Failed to disable gtk offload");
181
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800182}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800183
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530184
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185/**
186 * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function
187 * @nb: notifier block that was registered with the kernel
188 * @data: (unused) generic data that was registered with the kernel
189 * @arg: (unused) generic argument that was registered with the kernel
190 *
191 * This is a callback function that is registered with the kernel via
192 * register_inet6addr_notifier() which allows the driver to be
193 * notified when there is an IPv6 address change.
194 *
195 * Return: NOTIFY_DONE to indicate we don't care what happens with
196 * other callbacks
197 */
198static int __wlan_hdd_ipv6_changed(struct notifier_block *nb,
Dustin Brownf13b8c32017-05-19 17:23:08 -0700199 unsigned long data, void *arg)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800200{
201 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
202 struct net_device *ndev = ifa->idev->dev;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700203 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700204 struct hdd_context *hdd_ctx;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700205 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800206
Jeff Johnson158c8d02016-10-31 13:11:48 -0700207 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530208
Dustin Brownf13b8c32017-05-19 17:23:08 -0700209 errno = hdd_validate_adapter(adapter);
210 if (errno)
211 goto exit;
212
213 if (adapter->dev == ndev &&
214 (adapter->device_mode == QDF_STA_MODE ||
215 adapter->device_mode == QDF_P2P_CLIENT_MODE ||
216 adapter->device_mode == QDF_NDI_MODE)) {
217 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
218 errno = wlan_hdd_validate_context(hdd_ctx);
219 if (errno)
220 goto exit;
221
Nachiket Kukadec9045fe2017-06-19 15:14:43 +0530222 /* Ignore if the interface is down */
223 if (!(ndev->flags & IFF_UP)) {
224 hdd_err("Rcvd change addr request on %s(flags 0x%X)",
225 ndev->name, ndev->flags);
226 hdd_err("NETDEV Interface is down, ignoring...");
227 goto exit;
228 }
229
Dustin Brownf13b8c32017-05-19 17:23:08 -0700230 hdd_debug("invoking sme_dhcp_done_ind");
231 sme_dhcp_done_ind(hdd_ctx->hHal, adapter->sessionId);
232 schedule_work(&adapter->ipv6NotifierWorkQueue);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800233 }
234
Dustin Brownf13b8c32017-05-19 17:23:08 -0700235exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530236 EXIT();
Dustin Brownf13b8c32017-05-19 17:23:08 -0700237
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800238 return NOTIFY_DONE;
239}
240
241/**
242 * wlan_hdd_ipv6_changed() - IPv6 change notifier callback
243 * @nb: pointer to notifier block
244 * @data: data
245 * @arg: arg
246 *
247 * This is the IPv6 notifier callback function gets invoked
248 * if any change in IP and then invoke the function @__wlan_hdd_ipv6_changed
249 * to reconfigure the offload parameters.
250 *
251 * Return: 0 on success, error number otherwise.
252 */
253int wlan_hdd_ipv6_changed(struct notifier_block *nb,
254 unsigned long data, void *arg)
255{
256 int ret;
257
258 cds_ssr_protect(__func__);
259 ret = __wlan_hdd_ipv6_changed(nb, data, arg);
260 cds_ssr_unprotect(__func__);
261
262 return ret;
263}
264
265/**
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530266 * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses
267 * @idev: pointer to net device
268 * @ipv6addr: destination array to fill IPv6 addresses
269 * @ipv6addr_type: IPv6 Address type
270 * @count: number of IPv6 addresses
271 *
272 * This is the IPv6 utility function to populate unicast addresses.
273 *
274 * Return: 0 on success, error number otherwise.
275 */
276static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
277 uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN],
278 uint8_t *ipv6addr_type, uint32_t *count)
279{
280 struct inet6_ifaddr *ifa;
281 struct list_head *p;
282 uint32_t scope;
283
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700284 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530285 list_for_each(p, &idev->addr_list) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530286 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700287 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530288 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700289 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530290 ifa = list_entry(p, struct inet6_ifaddr, if_list);
291 if (ifa->flags & IFA_F_DADFAILED)
292 continue;
293 scope = ipv6_addr_src_scope(&ifa->addr);
294 switch (scope) {
295 case IPV6_ADDR_SCOPE_GLOBAL:
296 case IPV6_ADDR_SCOPE_LINKLOCAL:
297 qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
298 sizeof(ifa->addr.s6_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530299 ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE;
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800300 hdd_debug("Index %d scope = %s UC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530301 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
302 "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
303 *count += 1;
304 break;
305 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800306 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530307 }
308 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700309
310 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530311 return 0;
312}
313
314/**
315 * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses
316 * @idev: pointer to net device
317 * @ipv6addr: destination array to fill IPv6 addresses
318 * @ipv6addr_type: IPv6 Address type
319 * @count: number of IPv6 addresses
320 *
321 * This is the IPv6 utility function to populate anycast addresses.
322 *
323 * Return: 0 on success, error number otherwise.
324 */
325static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
326 uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN],
327 uint8_t *ipv6addr_type, uint32_t *count)
328{
329 struct ifacaddr6 *ifaca;
330 uint32_t scope;
331
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700332 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530333 for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530334 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700335 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530336 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700337 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530338 /* For anycast addr no DAD */
339 scope = ipv6_addr_src_scope(&ifaca->aca_addr);
340 switch (scope) {
341 case IPV6_ADDR_SCOPE_GLOBAL:
342 case IPV6_ADDR_SCOPE_LINKLOCAL:
343 qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
344 sizeof(ifaca->aca_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530345 ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE;
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800346 hdd_debug("Index %d scope = %s AC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530347 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
348 "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
349 *count += 1;
350 break;
351 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800352 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530353 }
354 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700355
356 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530357 return 0;
358}
359
Jeff Johnson75b737d2017-08-29 14:24:41 -0700360void hdd_enable_ns_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530361 enum pmo_offload_trigger trigger)
Dustin Brown2444ee62016-09-06 17:20:36 -0700362{
363 struct inet6_dev *in6_dev;
Dustin Brown2444ee62016-09-06 17:20:36 -0700364 QDF_STATUS status;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700365 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530366 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
367 struct pmo_ns_req *ns_req = NULL;
368 int err;
369
370 ENTER();
371 if (!psoc) {
372 hdd_err("psoc is NULL");
373 goto out;
374 }
Dustin Brown2444ee62016-09-06 17:20:36 -0700375
376 in6_dev = __in6_dev_get(adapter->dev);
377 if (NULL == in6_dev) {
378 hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530379 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700380 }
381
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530382 ns_req = qdf_mem_malloc(sizeof(*ns_req));
383 if (!ns_req) {
384 hdd_err("fail to allocate ns_req");
385 goto out;
386 }
387
388 ns_req->psoc = psoc;
389 ns_req->vdev_id = adapter->sessionId;
390 ns_req->trigger = trigger;
391 ns_req->count = 0;
392
Dustin Brown2444ee62016-09-06 17:20:36 -0700393 /* Unicast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530394 err = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
395 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700396 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530397 hdd_disable_ns_offload(adapter, trigger);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530398 hdd_debug("Max supported addresses: disabling NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530399 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700400 }
401
402 /* Anycast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530403 err = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
404 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700405 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530406 hdd_disable_ns_offload(adapter, trigger);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530407 hdd_debug("Max supported addresses: disabling NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530408 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700409 }
410
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530411 /* cache ns request */
412 status = pmo_ucfg_cache_ns_offload_req(ns_req);
413 if (status != QDF_STATUS_SUCCESS) {
414 hdd_err("Failed to cache ns request status: %d", status);
415 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700416 }
417
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530418 /* enable ns request */
419 status = pmo_ucfg_enable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
420 if (status != QDF_STATUS_SUCCESS)
Dustin Brown2444ee62016-09-06 17:20:36 -0700421 hdd_err("Failed to enable HostOffload feature with status: %d",
422 status);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530423 else
424 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
425out:
426 if (ns_req)
427 qdf_mem_free(ns_req);
428 EXIT();
429
Dustin Brown2444ee62016-09-06 17:20:36 -0700430}
431
Jeff Johnson75b737d2017-08-29 14:24:41 -0700432void hdd_disable_ns_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530433 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800434{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530435 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800436
437 ENTER();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530438 status = pmo_ucfg_flush_ns_offload_req(adapter->hdd_vdev);
439 if (status != QDF_STATUS_SUCCESS) {
440 hdd_err("Failed to flush NS Offload");
441 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800442 }
443
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530444 status = pmo_ucfg_disable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
445 if (status != QDF_STATUS_SUCCESS)
446 hdd_err("Failed to disable NS Offload");
Dustin Brown2444ee62016-09-06 17:20:36 -0700447 else
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530448 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD,
449 SIR_OFFLOAD_DISABLE);
450out:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800451 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530452
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800453}
454
455/**
456 * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function
457 * @work: registered work item
458 *
459 * This function performs the work initially trigged by a callback
460 * from the IPv6 netdev notifier. Since this means there has been a
461 * change in IPv6 state for the interface, the NS offload is
462 * reconfigured.
463 *
464 * Return: None
465 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700466static void __hdd_ipv6_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800467{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700468 struct hdd_context *hdd_ctx;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700469 struct hdd_adapter *adapter;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700470 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800471
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530472 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800473
Jeff Johnson75b737d2017-08-29 14:24:41 -0700474 adapter = container_of(work, struct hdd_adapter, ipv6NotifierWorkQueue);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700475 errno = hdd_validate_adapter(adapter);
476 if (errno)
477 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800478
Dustin Brownf13b8c32017-05-19 17:23:08 -0700479 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
480 errno = wlan_hdd_validate_context(hdd_ctx);
481 if (errno)
482 goto exit;
483
484 hdd_enable_ns_offload(adapter, pmo_ipv6_change_notify);
485
486exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530487 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800488}
489
490/**
491 * hdd_ipv6_notifier_work_queue() - IP V6 change notifier work handler
492 * @work: Pointer to work context
493 *
494 * Return: none
495 */
496void hdd_ipv6_notifier_work_queue(struct work_struct *work)
497{
498 cds_ssr_protect(__func__);
499 __hdd_ipv6_notifier_work_queue(work);
500 cds_ssr_unprotect(__func__);
501}
502
Jeff Johnson75b737d2017-08-29 14:24:41 -0700503static void hdd_enable_hw_filter(struct hdd_adapter *adapter)
Dustin Brown1224e212017-05-12 14:02:12 -0700504{
505 QDF_STATUS status;
506
507 ENTER();
508
509 status = pmo_ucfg_enable_hw_filter_in_fwr(adapter->hdd_vdev);
510 if (status != QDF_STATUS_SUCCESS)
511 hdd_info("Failed to enable hardware filter");
512
513 EXIT();
514}
515
Jeff Johnson75b737d2017-08-29 14:24:41 -0700516static void hdd_disable_hw_filter(struct hdd_adapter *adapter)
Dustin Brown1224e212017-05-12 14:02:12 -0700517{
518 QDF_STATUS status;
519
520 ENTER();
521
522 status = pmo_ucfg_disable_hw_filter_in_fwr(adapter->hdd_vdev);
523 if (status != QDF_STATUS_SUCCESS)
524 hdd_info("Failed to disable hardware filter");
525
526 EXIT();
527}
528
Jeff Johnson75b737d2017-08-29 14:24:41 -0700529void hdd_enable_host_offloads(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530530 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800531{
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530532 ENTER();
533
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530534 if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
535 hdd_info("offload is not supported on this vdev opmode: %d",
536 adapter->device_mode);
537 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800538 }
539
Rajeev Kumar9084cc82017-10-31 14:32:08 -0700540 if (!ucfg_pmo_is_vdev_connected(adapter->hdd_vdev)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530541 hdd_info("vdev is not connected");
542 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800543 }
544
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530545 hdd_info("enable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530546 hdd_enable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530547 hdd_enable_arp_offload(adapter, trigger);
548 hdd_enable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530549 hdd_enable_mc_addr_filtering(adapter, trigger);
Dustin Brown1224e212017-05-12 14:02:12 -0700550 hdd_enable_hw_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530551out:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530552 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530553
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800554}
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530555
Jeff Johnson75b737d2017-08-29 14:24:41 -0700556void hdd_disable_host_offloads(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530557 enum pmo_offload_trigger trigger)
558{
559 ENTER();
560
561 if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
562 hdd_info("offload is not supported on this vdev opmode: %d",
563 adapter->device_mode);
564 goto out;
565 }
566
Rajeev Kumar9084cc82017-10-31 14:32:08 -0700567 if (!ucfg_pmo_is_vdev_connected(adapter->hdd_vdev)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530568 hdd_info("vdev is not connected");
569 goto out;
570 }
571
572 hdd_info("disable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530573 hdd_disable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530574 hdd_disable_arp_offload(adapter, trigger);
575 hdd_disable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530576 hdd_disable_mc_addr_filtering(adapter, trigger);
Dustin Brown1224e212017-05-12 14:02:12 -0700577 hdd_disable_hw_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530578out:
579 EXIT();
580
581}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800582
583/**
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800584 * hdd_lookup_ifaddr() - Lookup interface address data by name
585 * @adapter: the adapter whose name should be searched for
586 *
587 * return in_ifaddr pointer on success, NULL for failure
588 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700589static struct in_ifaddr *hdd_lookup_ifaddr(struct hdd_adapter *adapter)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800590{
591 struct in_ifaddr *ifa;
592 struct in_device *in_dev;
593
594 if (!adapter) {
595 hdd_err("adapter is null");
596 return NULL;
597 }
598
599 in_dev = __in_dev_get_rtnl(adapter->dev);
600 if (!in_dev) {
601 hdd_err("Failed to get in_device");
602 return NULL;
603 }
604
605 /* lookup address data by interface name */
606 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
607 if (!strcmp(adapter->dev->name, ifa->ifa_label))
608 return ifa;
609 }
610
611 return NULL;
612}
613
614/**
615 * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address
616 * @adapter: the adapter whose IPv4 address is desired
617 * @ipv4_addr: the address of the array to copy the IPv4 address into
618 *
619 * return: zero for success; non-zero for failure
620 */
Jeff Johnsond6d1f632017-10-06 20:06:10 -0700621static int hdd_populate_ipv4_addr(struct hdd_adapter *adapter,
622 uint8_t *ipv4_addr)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800623{
624 struct in_ifaddr *ifa;
625 int i;
626
627 if (!adapter) {
628 hdd_err("adapter is null");
629 return -EINVAL;
630 }
631
632 if (!ipv4_addr) {
633 hdd_err("ipv4_addr is null");
634 return -EINVAL;
635 }
636
637 ifa = hdd_lookup_ifaddr(adapter);
638 if (!ifa || !ifa->ifa_local) {
639 hdd_err("ipv4 address not found");
640 return -EINVAL;
641 }
642
643 /* convert u32 to byte array */
644 for (i = 0; i < 4; i++)
645 ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff;
646
647 return 0;
648}
649
650/**
651 * hdd_set_grat_arp_keepalive() - Enable grat APR keepalive
652 * @adapter: the HDD adapter to configure
653 *
654 * This configures gratuitous APR keepalive based on the adapter's current
655 * connection information, specifically IPv4 address and BSSID
656 *
657 * return: zero for success, non-zero for failure
658 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700659static int hdd_set_grat_arp_keepalive(struct hdd_adapter *adapter)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800660{
661 QDF_STATUS status;
662 int exit_code;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700663 struct hdd_context *hdd_ctx;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700664 struct hdd_station_ctx *sta_ctx;
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800665 tSirKeepAliveReq req = {
666 .packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP,
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800667 .dest_macaddr = QDF_MAC_ADDR_BROADCAST_INITIALIZER,
668 };
669
670 if (!adapter) {
671 hdd_err("adapter is null");
672 return -EINVAL;
673 }
674
675 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
676 if (!hdd_ctx) {
677 hdd_err("hdd_ctx is null");
678 return -EINVAL;
679 }
680
681 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
682 if (!sta_ctx) {
683 hdd_err("sta_ctx is null");
684 return -EINVAL;
685 }
686
687 exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr);
688 if (exit_code) {
689 hdd_err("Failed to populate ipv4 address");
690 return exit_code;
691 }
692
Dustin Brown6b4643d2017-02-09 12:19:28 -0800693 /* according to RFC5227, sender/target ip address should be the same */
694 qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr,
695 sizeof(req.destIpv4Addr));
696
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800697 qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssId);
698 req.timePeriod = hdd_ctx->config->infraStaKeepAlivePeriod;
699 req.sessionId = adapter->sessionId;
700
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800701 hdd_debug("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u",
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800702 req.hostIpv4Addr[0], req.hostIpv4Addr[1],
703 req.hostIpv4Addr[2], req.hostIpv4Addr[3]);
704
705 status = sme_set_keep_alive(hdd_ctx->hHal, req.sessionId, &req);
706 if (QDF_IS_STATUS_ERROR(status)) {
707 hdd_err("Failed to set keepalive");
708 return qdf_status_to_os_return(status);
709 }
710
711 return 0;
712}
713
714/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800715 * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function
716 * @work: registered work item
717 *
718 * This function performs the work initially trigged by a callback
719 * from the IPv4 netdev notifier. Since this means there has been a
720 * change in IPv4 state for the interface, the ARP offload is
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530721 * reconfigured. Also, Updates the HLP IE info with IP address info
722 * to fw if LFR3 is enabled
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800723 *
724 * Return: None
725 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700726static void __hdd_ipv4_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800727{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700728 struct hdd_context *hdd_ctx;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700729 struct hdd_adapter *adapter;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700730 int errno;
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530731 struct hdd_wext_state *wext_state;
732 tCsrRoamProfile *roam_profile;
733 struct in_ifaddr *ifa;
Dustin Brownb6b0f182017-03-08 13:08:27 -0800734
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530735 ENTER();
Dustin Brownb6b0f182017-03-08 13:08:27 -0800736
Jeff Johnson75b737d2017-08-29 14:24:41 -0700737 adapter = container_of(work, struct hdd_adapter, ipv4NotifierWorkQueue);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700738 errno = hdd_validate_adapter(adapter);
739 if (errno)
740 goto exit;
Dustin Brownb6b0f182017-03-08 13:08:27 -0800741
742 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700743 errno = wlan_hdd_validate_context(hdd_ctx);
744 if (errno)
745 goto exit;
746
747 hdd_enable_arp_offload(adapter, pmo_ipv4_change_notify);
748
Dustin Brownb6b0f182017-03-08 13:08:27 -0800749 if (hdd_ctx->config->sta_keepalive_method == HDD_STA_KEEPALIVE_GRAT_ARP)
750 hdd_set_grat_arp_keepalive(adapter);
751
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530752 hdd_debug("FILS Roaming support: %d",
753 hdd_ctx->is_fils_roaming_supported);
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530754 wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
755 roam_profile = &wext_state->roamProfile;
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530756
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530757 ifa = hdd_lookup_ifaddr(adapter);
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530758 if (ifa && hdd_ctx->is_fils_roaming_supported)
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530759 sme_send_hlp_ie_info(hdd_ctx->hHal, adapter->sessionId,
760 roam_profile, ifa->ifa_local);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700761exit:
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530762 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800763}
764
765/**
766 * hdd_ipv4_notifier_work_queue() - IP V4 change notifier work handler
767 * @work: Pointer to work context
768 *
769 * Return: none
770 */
771void hdd_ipv4_notifier_work_queue(struct work_struct *work)
772{
773 cds_ssr_protect(__func__);
774 __hdd_ipv4_notifier_work_queue(work);
775 cds_ssr_unprotect(__func__);
776}
777
778/**
779 * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function
780 * @nb: notifier block that was registered with the kernel
781 * @data: (unused) generic data that was registered with the kernel
782 * @arg: (unused) generic argument that was registered with the kernel
783 *
784 * This is a callback function that is registered with the kernel via
785 * register_inetaddr_notifier() which allows the driver to be
786 * notified when there is an IPv4 address change.
787 *
788 * Return: NOTIFY_DONE to indicate we don't care what happens with
789 * other callbacks
790 */
791static int __wlan_hdd_ipv4_changed(struct notifier_block *nb,
792 unsigned long data, void *arg)
793{
794 struct in_ifaddr *ifa = (struct in_ifaddr *)arg;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800795 struct net_device *ndev = ifa->ifa_dev->dev;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700796 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700797 struct hdd_context *hdd_ctx;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700798 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800799
Jeff Johnson158c8d02016-10-31 13:11:48 -0700800 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530801
Dustin Brownf13b8c32017-05-19 17:23:08 -0700802 errno = hdd_validate_adapter(adapter);
803 if (errno)
804 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800805
Dustin Brownf13b8c32017-05-19 17:23:08 -0700806 if (adapter->dev == ndev &&
807 (adapter->device_mode == QDF_STA_MODE ||
808 adapter->device_mode == QDF_P2P_CLIENT_MODE ||
809 adapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800810
Dustin Brownf13b8c32017-05-19 17:23:08 -0700811 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
812 errno = wlan_hdd_validate_context(hdd_ctx);
813 if (errno)
814 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800815
Nachiket Kukadec9045fe2017-06-19 15:14:43 +0530816 /* Ignore if the interface is down */
817 if (!(ndev->flags & IFF_UP)) {
818 hdd_err("Rcvd change addr request on %s(flags 0x%X)",
819 ndev->name, ndev->flags);
820 hdd_err("NETDEV Interface is down, ignoring...");
821 goto exit;
822 }
Padma, Santhosh Kumar8392fb42017-03-17 12:35:27 +0530823 hdd_debug("invoking sme_dhcp_done_ind");
Dustin Brownf13b8c32017-05-19 17:23:08 -0700824 sme_dhcp_done_ind(hdd_ctx->hHal, adapter->sessionId);
Abhishek Singhca408032016-09-13 15:26:12 +0530825
Dustin Brownf13b8c32017-05-19 17:23:08 -0700826 if (!hdd_ctx->config->fhostArpOffload) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800827 hdd_debug("Offload not enabled ARPOffload=%d",
Dustin Brownf13b8c32017-05-19 17:23:08 -0700828 hdd_ctx->config->fhostArpOffload);
829 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800830 }
831
Dustin Brownf13b8c32017-05-19 17:23:08 -0700832 ifa = hdd_lookup_ifaddr(adapter);
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800833 if (ifa && ifa->ifa_local)
Dustin Brownf13b8c32017-05-19 17:23:08 -0700834 schedule_work(&adapter->ipv4NotifierWorkQueue);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800835 }
Dustin Brownf13b8c32017-05-19 17:23:08 -0700836
837exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530838 EXIT();
Dustin Brownf13b8c32017-05-19 17:23:08 -0700839
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840 return NOTIFY_DONE;
841}
842
843/**
844 * wlan_hdd_ipv4_changed() - IPv4 change notifier callback
845 * @nb: pointer to notifier block
846 * @data: data
847 * @arg: arg
848 *
849 * This is the IPv4 notifier callback function gets invoked
850 * if any change in IP and then invoke the function @__wlan_hdd_ipv4_changed
851 * to reconfigure the offload parameters.
852 *
853 * Return: 0 on success, error number otherwise.
854 */
855int wlan_hdd_ipv4_changed(struct notifier_block *nb,
856 unsigned long data, void *arg)
857{
858 int ret;
859
860 cds_ssr_protect(__func__);
861 ret = __wlan_hdd_ipv4_changed(nb, data, arg);
862 cds_ssr_unprotect(__func__);
863
864 return ret;
865}
866
867/**
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530868 * hdd_get_ipv4_local_interface() - get ipv4 local interafce from iface list
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700869 * @adapter: Adapter context for which ARP offload is to be configured
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800870 *
871 * Return:
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530872 * ifa - on successful operation,
873 * NULL - on failure of operation
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800874 */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530875static struct in_ifaddr *hdd_get_ipv4_local_interface(
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700876 struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800877{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530878 struct in_ifaddr **ifap = NULL;
879 struct in_ifaddr *ifa = NULL;
880 struct in_device *in_dev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800881
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700882 in_dev = __in_dev_get_rtnl(adapter->dev);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530883 if (in_dev) {
884 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
885 ifap = &ifa->ifa_next) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700886 if (!strcmp(adapter->dev->name, ifa->ifa_label)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530887 /* if match break */
888 return ifa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800889 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800890 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530891 }
892 ifa = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800893
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530894 return ifa;
895}
896
Jeff Johnson75b737d2017-08-29 14:24:41 -0700897void hdd_enable_arp_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530898 enum pmo_offload_trigger trigger)
899{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700900 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530901 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
902 QDF_STATUS status;
903 struct pmo_arp_req *arp_req = NULL;
904 struct in_ifaddr *ifa = NULL;
905
906 ENTER();
907 arp_req = qdf_mem_malloc(sizeof(*arp_req));
908 if (!arp_req) {
909 hdd_err("cannot allocate arp_req");
910 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800911 }
Jeff Johnson68755312017-02-10 11:46:55 -0800912
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530913 arp_req->psoc = psoc;
914 arp_req->vdev_id = adapter->sessionId;
915 arp_req->trigger = trigger;
Jeff Johnson68755312017-02-10 11:46:55 -0800916
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530917 ifa = hdd_get_ipv4_local_interface(adapter);
918 if (ifa && ifa->ifa_local) {
919 arp_req->ipv4_addr = (uint32_t)ifa->ifa_local;
920 status = pmo_ucfg_cache_arp_offload_req(arp_req);
921 if (status == QDF_STATUS_SUCCESS) {
922 status = pmo_ucfg_enable_arp_offload_in_fwr(
923 adapter->hdd_vdev, trigger);
924 if (status == QDF_STATUS_SUCCESS)
925 hdd_wlan_offload_event(
926 PMO_IPV4_ARP_REPLY_OFFLOAD,
927 PMO_OFFLOAD_ENABLE);
928 else
929 hdd_info("fail to enable arp offload in fwr");
930 } else
931 hdd_info("fail to cache arp offload request");
932 } else {
933 hdd_notice("IP Address is not assigned");
934 status = QDF_STATUS_NOT_INITIALIZED;
935 }
936out:
937 if (arp_req)
938 qdf_mem_free(arp_req);
939 EXIT();
940
941}
942
Jeff Johnson75b737d2017-08-29 14:24:41 -0700943void hdd_disable_arp_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530944 enum pmo_offload_trigger trigger)
945{
946 QDF_STATUS status;
947
948 ENTER();
949 status = pmo_ucfg_flush_arp_offload_req(adapter->hdd_vdev);
950 if (status != QDF_STATUS_SUCCESS) {
951 hdd_err("Failed to flush arp Offload");
952 goto out;
Jeff Johnson68755312017-02-10 11:46:55 -0800953 }
954
Jeff Johnsond6d1f632017-10-06 20:06:10 -0700955 status = pmo_ucfg_disable_arp_offload_in_fwr(adapter->hdd_vdev,
956 trigger);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530957 if (status == QDF_STATUS_SUCCESS)
958 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD,
959 PMO_OFFLOAD_DISABLE);
960 else
961 hdd_info("fail to disable arp offload");
962out:
963 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800964}
965
Jeff Johnson75b737d2017-08-29 14:24:41 -0700966void hdd_enable_mc_addr_filtering(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530967 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800968{
Jeff Johnson399c6272017-08-30 10:51:00 -0700969 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530970 QDF_STATUS status;
971 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800972
Ravi Joshi24477b72016-07-19 15:45:09 -0700973 ENTER();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530974 if (wlan_hdd_validate_context(hdd_ctx))
975 goto out;
Ravi Joshi24477b72016-07-19 15:45:09 -0700976
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530977 status = pmo_ucfg_enable_mc_addr_filtering_in_fwr(psoc,
978 adapter->sessionId, trigger);
979 if (status != QDF_STATUS_SUCCESS)
980 hdd_info("failed to enable mc list status %d", status);
981out:
Ravi Joshi24477b72016-07-19 15:45:09 -0700982 EXIT();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530983
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800984}
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530985
Jeff Johnson75b737d2017-08-29 14:24:41 -0700986void hdd_disable_mc_addr_filtering(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530987 enum pmo_offload_trigger trigger)
988{
Jeff Johnson399c6272017-08-30 10:51:00 -0700989 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530990 QDF_STATUS status = QDF_STATUS_SUCCESS;
991 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
992
993 ENTER();
994 if (wlan_hdd_validate_context(hdd_ctx))
995 goto out;
996
997 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
998 adapter->sessionId, trigger);
999 if (status != QDF_STATUS_SUCCESS)
1000 hdd_info("failed to disable mc list status %d", status);
1001out:
1002 EXIT();
1003
1004}
1005
1006int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config)
1007{
1008 QDF_STATUS status;
1009 int ret = 0;
1010
1011 ENTER();
1012 /* cache mc addr list */
1013 status = pmo_ucfg_cache_mc_addr_list(mc_list_config);
1014 if (status != QDF_STATUS_SUCCESS) {
1015 hdd_info("fail to cache mc list status %d", status);
1016 ret = -EINVAL;
1017 }
1018 EXIT();
1019
1020 return ret;
1021}
1022
Jeff Johnson75b737d2017-08-29 14:24:41 -07001023void hdd_disable_and_flush_mc_addr_list(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301024 enum pmo_offload_trigger trigger)
1025{
Jeff Johnson399c6272017-08-30 10:51:00 -07001026 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301027 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
1028 QDF_STATUS status = QDF_STATUS_SUCCESS;
1029
1030 ENTER();
1031 /* disable mc list first */
1032 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
1033 adapter->sessionId, trigger);
1034 if (status != QDF_STATUS_SUCCESS)
1035 hdd_info("fail to disable mc list");
1036
1037 /* flush mc list */
1038 status = pmo_ucfg_flush_mc_addr_list(psoc, adapter->sessionId);
1039 if (status != QDF_STATUS_SUCCESS)
1040 hdd_info("fail to flush mc list status %d", status);
1041 EXIT();
1042
1043 return;
1044
1045}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046
1047/**
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001048 * hdd_update_conn_state_mask(): record info needed by wma_suspend_req
1049 * @adapter: adapter to get info from
1050 * @conn_state_mask: mask of connection info
1051 *
1052 * currently only need to send connection info.
1053 */
Jeff Johnsond6d1f632017-10-06 20:06:10 -07001054static void hdd_update_conn_state_mask(struct hdd_adapter *adapter,
1055 uint32_t *conn_state_mask)
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001056{
1057
1058 eConnectionState connState;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07001059 struct hdd_station_ctx *sta_ctx;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301060
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001061 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301062
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001063 connState = sta_ctx->conn_info.connState;
1064
1065 if (connState == eConnectionState_Associated ||
1066 connState == eConnectionState_IbssConnected)
1067 *conn_state_mask |= (1 << adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001068}
1069
1070/**
1071 * hdd_suspend_wlan() - Driver suspend function
1072 * @callback: Callback function to invoke when driver is ready to suspend
1073 * @callbackContext: Context to pass back to @callback function
1074 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301075 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001076 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301077static int
1078hdd_suspend_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001079{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001080 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001081
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301082 QDF_STATUS status;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001083 struct hdd_adapter *adapter = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001085 uint32_t conn_state_mask = 0;
Jeff Johnson4f7f7c62017-10-05 08:53:41 -07001086
Jeff Johnsonc3273322016-07-06 15:28:17 -07001087 hdd_info("WLAN being suspended by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001088
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001089 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1090 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001091 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301092 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001093 }
1094
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301095 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001096 hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001097 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301098 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001099 }
1100
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001101 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301102 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001103 adapter = pAdapterNode->adapter;
1104 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
1105 hdd_err("invalid session id: %d", adapter->sessionId);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301106 goto next_adapter;
1107 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108
1109 /* stop all TX queues before suspend */
Srinivas Girigowda6598eea2017-07-06 19:26:19 -07001110 hdd_info("Disabling queues");
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001111 wlan_hdd_netif_queue_control(adapter,
Himanshu Agarwal865201d2017-04-12 15:45:31 +05301112 WLAN_STOP_ALL_NETIF_QUEUE,
1113 WLAN_CONTROL_PATH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001114
Hanumanth Reddy Pothula3def8942017-10-05 16:19:36 +05301115 if (adapter->device_mode == QDF_STA_MODE)
1116 status = hdd_enable_default_pkt_filters(adapter);
1117
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001118 /* Configure supported OffLoads */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001119 hdd_enable_host_offloads(adapter, pmo_apps_suspend);
1120 hdd_update_conn_state_mask(adapter, &conn_state_mask);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301121next_adapter:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001122 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, &pNext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001123 pAdapterNode = pNext;
1124 }
1125
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001126 status = pmo_ucfg_psoc_user_space_suspend_req(hdd_ctx->hdd_psoc,
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301127 QDF_SYSTEM_SUSPEND);
1128 if (status != QDF_STATUS_SUCCESS)
1129 return -EAGAIN;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001130
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001131 hdd_ctx->hdd_wlan_suspended = true;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301132 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001133
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301134 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001135}
1136
1137/**
1138 * hdd_resume_wlan() - Driver resume function
1139 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301140 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001141 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301142static int hdd_resume_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001143{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001144 struct hdd_context *hdd_ctx;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001145 struct hdd_adapter *adapter = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001146 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301147 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001148
Dustin Brown2d228232016-09-22 15:06:19 -07001149 hdd_info("WLAN being resumed by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001150
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001151 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1152 if (!hdd_ctx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001153 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301154 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001155 }
1156
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301157 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001158 hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001159 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301160 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001161 }
1162
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001163 hdd_ctx->hdd_wlan_suspended = false;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301164 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001165
1166 /*loop through all adapters. Concurrency */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001167 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001168
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301169 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001170 adapter = pAdapterNode->adapter;
1171 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
1172 hdd_err("invalid session id: %d", adapter->sessionId);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301173 goto next_adapter;
1174 }
1175 /* Disable supported OffLoads */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001176 hdd_disable_host_offloads(adapter, pmo_apps_resume);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001177
1178 /* wake the tx queues */
Dustin Brown2d228232016-09-22 15:06:19 -07001179 hdd_info("Enabling queues");
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001180 wlan_hdd_netif_queue_control(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001181 WLAN_WAKE_ALL_NETIF_QUEUE,
1182 WLAN_CONTROL_PATH);
1183
Hanumanth Reddy Pothula3def8942017-10-05 16:19:36 +05301184 if (adapter->device_mode == QDF_STA_MODE)
1185 status = hdd_disable_default_pkt_filters(adapter);
1186
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301187next_adapter:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001188 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, &pNext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001189 pAdapterNode = pNext;
1190 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001191 hdd_ipa_resume(hdd_ctx);
1192 status = pmo_ucfg_psoc_user_space_resume_req(hdd_ctx->hdd_psoc,
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301193 QDF_SYSTEM_SUSPEND);
1194 if (status != QDF_STATUS_SUCCESS)
1195 return -EAGAIN;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001196
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301197 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001198}
1199
1200/**
Komal Seelam78ff65a2016-08-18 15:25:24 +05301201 * hdd_svc_fw_shutdown_ind() - API to send FW SHUTDOWN IND to Userspace
1202 *
1203 * @dev: Device Pointer
1204 *
1205 * Return: None
1206 */
1207void hdd_svc_fw_shutdown_ind(struct device *dev)
1208{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001209 struct hdd_context *hdd_ctx;
Komal Seelam78ff65a2016-08-18 15:25:24 +05301210
1211 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1212
1213 hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
1214 WLAN_SVC_FW_SHUTDOWN_IND,
1215 NULL, 0) : 0;
1216}
1217
1218/**
Arun Khandavallicc544b32017-01-30 19:52:16 +05301219 * hdd_ssr_restart_sap() - restart sap on SSR
1220 * @hdd_ctx: hdd context
1221 *
1222 * Return: nothing
1223 */
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001224static void hdd_ssr_restart_sap(struct hdd_context *hdd_ctx)
Arun Khandavallicc544b32017-01-30 19:52:16 +05301225{
1226 QDF_STATUS status;
1227 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Jeff Johnson75b737d2017-08-29 14:24:41 -07001228 struct hdd_adapter *adapter;
Arun Khandavallicc544b32017-01-30 19:52:16 +05301229
1230 ENTER();
1231
1232 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
1233 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Jeff Johnson57eb2732017-10-02 11:40:20 -07001234 adapter = adapter_node->adapter;
Arun Khandavallicc544b32017-01-30 19:52:16 +05301235 if (adapter && adapter->device_mode == QDF_SAP_MODE) {
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001236 if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001237 hdd_debug("Restart prev SAP session");
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001238 wlan_hdd_start_sap(adapter, true);
1239 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05301240 }
1241 status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next);
1242 adapter_node = next;
1243 }
1244
1245 EXIT();
1246}
1247
1248/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001249 * hdd_wlan_shutdown() - HDD SSR shutdown function
1250 *
1251 * This function is called by the HIF to shutdown the driver during SSR.
1252 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301253 * Return: QDF_STATUS_SUCCESS if the driver was shut down,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001254 * or an error status otherwise
1255 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301256QDF_STATUS hdd_wlan_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001257{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001258 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001259 p_cds_sched_context cds_sched_context = NULL;
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001260 QDF_STATUS qdf_status;
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001261 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001262
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001263 hdd_info("WLAN driver shutting down!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001264
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265 /* Get the HDD context. */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001266 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1267 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001268 hdd_err("HDD context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301269 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001270 }
1271
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001272 policy_mgr_clear_concurrent_session_count(hdd_ctx->hdd_psoc);
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301273
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001274 hdd_debug("Invoking packetdump deregistration API");
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301275 wlan_deregister_txrx_packetdump();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001276 wlan_cfg80211_cleanup_scan_queue(hdd_ctx->hdd_pdev);
1277 hdd_reset_all_adapters(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001278
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301279 /* Flush cached rx frame queue */
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001280 if (soc)
1281 cdp_flush_cache_rx_queue(soc);
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301282
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301283 /* De-register the HDD callbacks */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001284 hdd_deregister_cb(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001285
1286 cds_sched_context = get_cds_sched_ctxt();
1287
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001288 if (hdd_ctx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001289 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001290 hdd_ctx->is_scheduler_suspended = false;
Sameer Thalappil2767f442017-09-14 13:26:46 -07001291 hdd_ctx->isWiphySuspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001292 }
1293#ifdef QCA_CONFIG_SMP
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001294 if (true == hdd_ctx->is_ol_rx_thread_suspended) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001295 complete(&cds_sched_context->ol_resume_rx_event);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001296 hdd_ctx->is_ol_rx_thread_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001297 }
1298#endif
1299
Jeff Johnson7d562272017-09-13 15:12:54 -07001300 qdf_status = cds_sched_close();
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001301 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1302 hdd_err("Failed to close CDS Scheduler");
1303 QDF_ASSERT(false);
1304 }
1305
Manikandan Mohan71844ea2017-07-05 21:51:08 -07001306 hdd_ipa_uc_ssr_deinit();
Nitesh Shah61c10d92016-10-19 19:29:15 +05301307
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001308 hdd_bus_bandwidth_destroy(hdd_ctx);
Prashanth Bhattaab004382016-10-11 16:08:11 -07001309
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001310 hdd_wlan_stop_modules(hdd_ctx, false);
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301311
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001312 hdd_lpass_notify_stop(hdd_ctx);
Yuanyuan Liu3e918e52016-08-17 15:41:35 -07001313
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001314 wlan_objmgr_print_ref_all_objects_per_psoc(hdd_ctx->hdd_psoc);
Yue Ma2be12872017-06-02 13:06:58 -07001315
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001316 hdd_info("WLAN driver shutdown complete");
Yue Ma2be12872017-06-02 13:06:58 -07001317
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301318 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001319}
1320
Sen, Devendra154b3c42017-02-13 20:44:15 +05301321#ifdef FEATURE_WLAN_DIAG_SUPPORT
1322/**
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301323 * hdd_wlan_ssr_reinit_event()- send ssr reinit state
1324 *
1325 * This Function send send ssr reinit state diag event
1326 *
1327 * Return: void.
1328 */
Sen, Devendra154b3c42017-02-13 20:44:15 +05301329static void hdd_wlan_ssr_reinit_event(void)
1330{
1331 WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit);
1332 qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit));
1333 ssr_reinit.status = SSR_SUB_SYSTEM_REINIT;
1334 WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit,
1335 EVENT_WLAN_SSR_REINIT_SUBSYSTEM);
1336}
1337#else
1338static inline void hdd_wlan_ssr_reinit_event(void)
1339{
1340
1341}
1342#endif
1343
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001344/**
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301345 * hdd_send_default_scan_ies - send default scan ies to fw
1346 *
1347 * This function is used to send default scan ies to fw
1348 * in case of wlan re-init
1349 *
1350 * Return: void
1351 */
1352static void hdd_send_default_scan_ies(struct hdd_context *hdd_ctx)
1353{
1354 hdd_adapter_list_node_t *adapter_node, *next;
1355 struct hdd_adapter *adapter;
1356 QDF_STATUS status;
1357
1358 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
1359 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Jeff Johnson57eb2732017-10-02 11:40:20 -07001360 adapter = adapter_node->adapter;
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301361 if (hdd_is_interface_up(adapter) &&
1362 (adapter->device_mode == QDF_STA_MODE ||
1363 adapter->device_mode == QDF_P2P_DEVICE_MODE)) {
1364 sme_set_default_scan_ie(hdd_ctx->hHal,
1365 adapter->sessionId,
1366 adapter->scan_info.default_scan_ies,
1367 adapter->scan_info.default_scan_ies_len);
1368 }
1369 status = hdd_get_next_adapter(hdd_ctx, adapter_node,
1370 &next);
1371 adapter_node = next;
1372 }
1373}
1374
1375/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001376 * hdd_wlan_re_init() - HDD SSR re-init function
1377 *
1378 * This function is called by the HIF to re-initialize the driver after SSR.
1379 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301380 * Return: QDF_STATUS_SUCCESS if the driver was re-initialized,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001381 * or an error status otherwise
1382 */
Arun Khandavallifae92942016-08-01 13:31:08 +05301383QDF_STATUS hdd_wlan_re_init(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001384{
Arun Khandavallifae92942016-08-01 13:31:08 +05301385
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001386 struct hdd_context *hdd_ctx = NULL;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001387 struct hdd_adapter *adapter;
Arun Khandavallifae92942016-08-01 13:31:08 +05301388 int ret;
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301389 bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001390
1391 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1392
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001393 /* Get the HDD context */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001394 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1395 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001396 hdd_err("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001397 goto err_re_init;
1398 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001399 bug_on_reinit_failure = hdd_ctx->config->bug_on_reinit_failure;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001400
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001401 /* The driver should always be initialized in STA mode after SSR */
1402 hdd_set_conparam(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001403 /* Try to get an adapter from mode ID */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001404 adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE);
1405 if (!adapter) {
1406 adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
1407 if (!adapter) {
1408 adapter = hdd_get_adapter(hdd_ctx, QDF_IBSS_MODE);
1409 if (!adapter) {
1410 adapter = hdd_get_adapter(hdd_ctx,
1411 QDF_MONITOR_MODE);
1412 if (!adapter)
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001413 hdd_err("Failed to get Adapter!");
Arunk Khandavalli062fb032017-10-04 12:18:15 +05301414 }
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301415
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001416 }
1417 }
1418
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001419 if (hdd_ctx->config->enable_dp_trace)
1420 hdd_dp_trace_init(hdd_ctx->config);
Nirav Shahcc1f1ae2016-04-26 11:41:29 +05301421
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001422 hdd_bus_bandwidth_init(hdd_ctx);
Prashanth Bhattaab004382016-10-11 16:08:11 -07001423
Arun Khandavallicc544b32017-01-30 19:52:16 +05301424
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001425 ret = hdd_wlan_start_modules(hdd_ctx, adapter, true);
Arun Khandavallifae92942016-08-01 13:31:08 +05301426 if (ret) {
1427 hdd_err("Failed to start wlan after error");
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301428 goto err_re_init;
Arun Khandavallifae92942016-08-01 13:31:08 +05301429 }
1430
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001431 hdd_wlan_get_version(hdd_ctx, NULL, NULL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001432
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001433 wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
Wu Gao36717432016-11-21 15:09:48 +08001434 WLAN_SVC_FW_CRASHED_IND, NULL, 0);
1435
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001436 /* Restart all adapters */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001437 hdd_start_all_adapters(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001439 hdd_ctx->last_scan_reject_session_id = 0xFF;
1440 hdd_ctx->last_scan_reject_reason = 0;
1441 hdd_ctx->last_scan_reject_timestamp = 0;
1442 hdd_ctx->scan_reject_cnt = 0;
Sreelakshmi Konamkib53c6292017-03-01 13:13:23 +05301443
Selvaraj, Sridhar1c487562017-04-19 14:29:07 +05301444 hdd_set_roaming_in_progress(false);
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001445 complete(&adapter->roaming_comp_var);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001446 hdd_ctx->btCoexModeSet = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001447
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001448 /* Allow the phone to go to sleep */
1449 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05301450 /* set chip power save failure detected callback */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001451 sme_set_chip_pwr_save_fail_cb(hdd_ctx->hHal,
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05301452 hdd_chip_pwr_save_fail_detected_cb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001454 ret = hdd_register_cb(hdd_ctx);
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301455 if (ret) {
1456 hdd_err("Failed to register HDD callbacks!");
Chandrasekaran Manishekarcde33d72016-04-14 19:03:39 +05301457 goto err_cds_disable;
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301458 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001459
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001460 hdd_lpass_notify_start(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001461
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301462 hdd_send_default_scan_ies(hdd_ctx);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001463 hdd_info("WLAN host driver reinitiation completed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 goto success;
1465
1466err_cds_disable:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001467 hdd_wlan_stop_modules(hdd_ctx, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001468
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001469err_re_init:
1470 /* Allow the phone to go to sleep */
1471 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301472 if (bug_on_reinit_failure)
1473 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001474 return -EPERM;
1475
1476success:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001477 if (hdd_ctx->config->sap_internal_restart)
1478 hdd_ssr_restart_sap(hdd_ctx);
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301479
Sen, Devendra154b3c42017-02-13 20:44:15 +05301480 hdd_wlan_ssr_reinit_event();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301481 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001482}
1483
Jeff Johnson75b737d2017-08-29 14:24:41 -07001484int wlan_hdd_set_powersave(struct hdd_adapter *adapter,
Dustin Brownf660fb42016-09-09 12:04:00 -07001485 bool allow_power_save, uint32_t timeout)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001486{
1487 tHalHandle hal;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001488 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001489
1490 if (NULL == adapter) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001491 hdd_err("Adapter NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001492 return -ENODEV;
1493 }
1494
1495 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1496 if (!hdd_ctx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001497 hdd_err("hdd context is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001498 return -EINVAL;
1499 }
1500
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001501 hdd_debug("Allow power save: %d", allow_power_save);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001502 hal = WLAN_HDD_GET_HAL_CTX(adapter);
1503
Dustin Brown84411b02017-07-21 16:44:44 -07001504 /*
1505 * This is a workaround for defective AP's that send a disassoc
1506 * immediately after WPS connection completes. Defer powersave by a
1507 * small amount if the affected AP is detected.
1508 */
1509 if (allow_power_save &&
1510 adapter->device_mode == QDF_STA_MODE &&
Krunal Soni364e0872017-05-10 21:24:34 -07001511 !adapter->sessionCtx.station.ap_supports_immediate_power_save) {
1512 /* override user's requested flag */
Krunal Soni364e0872017-05-10 21:24:34 -07001513 allow_power_save = false;
Dustin Brown84411b02017-07-21 16:44:44 -07001514 timeout = AUTO_PS_DEFER_TIMEOUT_MS;
1515 hdd_debug("Defer power-save due to AP spec non-conformance");
Krunal Soni364e0872017-05-10 21:24:34 -07001516 }
1517
Dustin Brownf660fb42016-09-09 12:04:00 -07001518 if (allow_power_save) {
1519 if (QDF_STA_MODE == adapter->device_mode ||
1520 QDF_P2P_CLIENT_MODE == adapter->device_mode) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001521 hdd_debug("Disabling Auto Power save timer");
Dustin Brownf660fb42016-09-09 12:04:00 -07001522 sme_ps_disable_auto_ps_timer(
1523 WLAN_HDD_GET_HAL_CTX(adapter),
1524 adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001525 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001526
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001527 if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001528 hdd_debug("Wlan driver Entering Power save");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001529
1530 /*
1531 * Enter Power Save command received from GUI
1532 * this means DHCP is completed
1533 */
1534 sme_ps_enable_disable(hal, adapter->sessionId,
1535 SME_PS_ENABLE);
1536 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001537 hdd_debug("Power Save is not enabled in the cfg");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001538 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001539 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001540 hdd_debug("Wlan driver Entering Full Power");
Dustin Brownf660fb42016-09-09 12:04:00 -07001541
1542 /*
1543 * Enter Full power command received from GUI
1544 * this means we are disconnected
1545 */
1546 sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1547 adapter->sessionId);
1548 sme_ps_enable_disable(hal, adapter->sessionId, SME_PS_DISABLE);
1549 sme_ps_enable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
Dustin Brown84411b02017-07-21 16:44:44 -07001550 adapter->sessionId, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001551 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001552
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001553 return 0;
1554}
1555
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001556static void wlan_hdd_print_suspend_fail_stats(struct hdd_context *hdd_ctx)
Dustin Brown105d7902016-10-03 16:27:59 -07001557{
Dustin Brownd9322482017-01-09 12:46:03 -08001558 struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301559
Dustin Brown105d7902016-10-03 16:27:59 -07001560 hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d",
Dustin Brownd9322482017-01-09 12:46:03 -08001561 stats->suspend_fail[SUSPEND_FAIL_IPA],
1562 stats->suspend_fail[SUSPEND_FAIL_RADAR],
1563 stats->suspend_fail[SUSPEND_FAIL_ROAM],
1564 stats->suspend_fail[SUSPEND_FAIL_SCAN],
1565 stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]);
Dustin Brown105d7902016-10-03 16:27:59 -07001566}
1567
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001568void wlan_hdd_inc_suspend_stats(struct hdd_context *hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001569 enum suspend_fail_reason reason)
1570{
1571 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001572 hdd_ctx->suspend_resume_stats.suspend_fail[reason]++;
Dustin Brown105d7902016-10-03 16:27:59 -07001573 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
1574}
1575
Dustin Brown5fbb1052017-08-11 17:25:51 -07001576#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
1577static inline void
1578hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
1579{
1580 cfg80211_sched_scan_results(wiphy);
1581}
1582#else
1583static inline void
1584hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
1585{
1586 cfg80211_sched_scan_results(wiphy, reqid);
1587}
1588#endif
1589
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001590/**
1591 * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1592 * @wiphy: Pointer to wiphy
1593 *
1594 * This API is called when cfg80211 driver resumes driver updates
1595 * latest sched_scan scan result(if any) to cfg80211 database
1596 *
1597 * Return: integer status
1598 */
1599static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1600{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001601 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001602 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001603 hdd_adapter_list_node_t *pAdapterNode, *pNext;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301604 QDF_STATUS status = QDF_STATUS_SUCCESS;
Dustin Brownd9322482017-01-09 12:46:03 -08001605 int exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001606 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1607
1608 ENTER();
1609
Dustin Brownd9322482017-01-09 12:46:03 -08001610 if (cds_is_driver_recovering()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001611 hdd_debug("Driver is recovering; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001612 exit_code = 0;
1613 goto exit_with_code;
1614 }
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001615
Anurag Chouhan6d760662016-02-20 16:05:43 +05301616 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001617 hdd_err("Command not allowed in FTM mode");
Dustin Brownd9322482017-01-09 12:46:03 -08001618 exit_code = -EINVAL;
1619 goto exit_with_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001620 }
1621
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001622 exit_code = wlan_hdd_validate_context(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001623 if (exit_code) {
1624 hdd_err("Invalid HDD context");
1625 goto exit_with_code;
1626 }
Arun Khandavallifae92942016-08-01 13:31:08 +05301627
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001628 mutex_lock(&hdd_ctx->iface_change_lock);
1629 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1630 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001631 hdd_debug("Driver is not enabled; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001632 exit_code = 0;
1633 goto exit_with_code;
Arun Khandavallifae92942016-08-01 13:31:08 +05301634 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001635 mutex_unlock(&hdd_ctx->iface_change_lock);
Dustin Brownd9322482017-01-09 12:46:03 -08001636
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001637 pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_MEDIUM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001638
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301639 status = hdd_resume_wlan();
1640 if (status != QDF_STATUS_SUCCESS) {
1641 exit_code = 0;
1642 goto exit_with_code;
1643 }
Rajeev Kumareada0d02016-12-08 17:44:17 -08001644 /* Resume control path scheduler */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001645 if (hdd_ctx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001646 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001647 hdd_ctx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001648 }
1649#ifdef QCA_CONFIG_SMP
1650 /* Resume tlshim Rx thread */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001651 if (hdd_ctx->is_ol_rx_thread_suspended) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001652 complete(&cds_sched_context->ol_resume_rx_event);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001653 hdd_ctx->is_ol_rx_thread_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001654 }
1655#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001656
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301657 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301658 TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001659 NO_SESSION, hdd_ctx->isWiphySuspended));
1660 qdf_spin_lock(&hdd_ctx->sched_scan_lock);
1661 hdd_ctx->isWiphySuspended = false;
1662 if (true != hdd_ctx->isSchedScanUpdatePending) {
1663 qdf_spin_unlock(&hdd_ctx->sched_scan_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001664 hdd_debug("Return resume is not due to PNO indication");
Dustin Brownd9322482017-01-09 12:46:03 -08001665 goto exit_with_success;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001666 }
1667 /* Reset flag to avoid updatating cfg80211 data old results again */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001668 hdd_ctx->isSchedScanUpdatePending = false;
1669 qdf_spin_unlock(&hdd_ctx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001671 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301672 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001673 adapter = pAdapterNode->adapter;
1674 if ((NULL != adapter) &&
1675 (QDF_STA_MODE == adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001676 if (0 !=
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001677 wlan_hdd_cfg80211_update_bss(hdd_ctx->wiphy,
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001678 adapter, 0)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001679 hdd_warn("NO SCAN result");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001680 } else {
1681 /* Acquire wakelock to handle the case where
1682 * APP's tries to suspend immediately after
1683 * updating the scan results. Whis results in
1684 * app's is in suspended state and not able to
1685 * process the connect request to AP
1686 */
Sreelakshmi Konamki22528532016-09-06 16:34:50 +05301687 hdd_prevent_suspend_timeout(
Dustin Brownceed67e2017-05-26 11:57:31 -07001688 HDD_WAKELOCK_TIMEOUT_RESUME,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689 WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001690 hdd_sched_scan_results(hdd_ctx->wiphy, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001691 }
1692
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001693 hdd_debug("cfg80211 scan result database updated");
Dustin Brownd9322482017-01-09 12:46:03 -08001694 goto exit_with_success;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001696 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, &pNext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697 pAdapterNode = pNext;
1698 }
1699
Dustin Brownd9322482017-01-09 12:46:03 -08001700exit_with_success:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001701 hdd_ctx->suspend_resume_stats.resumes++;
Dustin Brownd9322482017-01-09 12:46:03 -08001702 exit_code = 0;
1703
1704exit_with_code:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301705 EXIT();
Dustin Brownd9322482017-01-09 12:46:03 -08001706 return exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001707}
1708
1709/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001710 * wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1711 * @wiphy: Pointer to wiphy
1712 *
1713 * This API is called when cfg80211 driver resumes driver updates
1714 * latest sched_scan scan result(if any) to cfg80211 database
1715 *
1716 * Return: integer status
1717 */
1718int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1719{
1720 int ret;
1721
1722 cds_ssr_protect(__func__);
1723 ret = __wlan_hdd_cfg80211_resume_wlan(wiphy);
1724 cds_ssr_unprotect(__func__);
1725
1726 return ret;
1727}
1728
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001729static void hdd_suspend_cb(void)
1730{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001731 struct hdd_context *hdd_ctx;
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001732
1733 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1734 if (!hdd_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001735 hdd_err("HDD context is NULL");
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001736 return;
1737 }
1738
1739 complete(&hdd_ctx->mc_sus_event_var);
1740}
1741
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742/**
1743 * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1744 * @wiphy: Pointer to wiphy
1745 * @wow: Pointer to wow
1746 *
1747 * This API is called when cfg80211 driver suspends
1748 *
1749 * Return: integer status
1750 */
1751static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1752 struct cfg80211_wowlan *wow)
1753{
1754#ifdef QCA_CONFIG_SMP
1755#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */
1756#endif
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001757 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1759 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001760 struct hdd_adapter *adapter;
Jeff Johnson5287de52017-10-28 12:23:06 -07001761 struct hdd_scan_info *scan_info;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301762 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763 int rc;
1764
1765 ENTER();
1766
Anurag Chouhan6d760662016-02-20 16:05:43 +05301767 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001768 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001769 return -EINVAL;
1770 }
1771
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001772 rc = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301773 if (0 != rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001774 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001776 mutex_lock(&hdd_ctx->iface_change_lock);
1777 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1778 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001779 hdd_debug("Driver Modules not Enabled ");
Arun Khandavallifae92942016-08-01 13:31:08 +05301780 return 0;
1781 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001782 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavallifae92942016-08-01 13:31:08 +05301783
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784 /* If RADAR detection is in progress (HDD), prevent suspend. The flag
1785 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true
1786 * until CAC is done for a SoftAP which is in started state.
1787 */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001788 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301789 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001790 adapter = pAdapterNode->adapter;
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301791
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001792 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
1793 hdd_err("invalid session id: %d", adapter->sessionId);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301794 goto next_adapter;
1795 }
1796
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001797 if (QDF_SAP_MODE == adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798 if (BSS_START ==
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07001799 WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter)->bss_state &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001800 true ==
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001801 WLAN_HDD_GET_AP_CTX_PTR(adapter)->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001802 dfs_cac_block_tx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001803 hdd_err("RADAR detection in progress, do not allow suspend");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001804 wlan_hdd_inc_suspend_stats(hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001805 SUSPEND_FAIL_RADAR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001806 return -EAGAIN;
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001807 } else if (!hdd_ctx->config->enableSapSuspend) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001808 /* return -EOPNOTSUPP if SAP does not support
1809 * suspend
1810 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001811 hdd_err("SAP does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001812 return -EOPNOTSUPP;
1813 }
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001814 } else if (QDF_P2P_GO_MODE == adapter->device_mode) {
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001815 if (!hdd_ctx->config->enableSapSuspend) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001816 /* return -EOPNOTSUPP if GO does not support
1817 * suspend
1818 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001819 hdd_err("GO does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001820 return -EOPNOTSUPP;
1821 }
1822 }
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301823next_adapter:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001824 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, &pNext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001825 pAdapterNode = pNext;
1826 }
1827
1828 /* Stop ongoing scan on each interface */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001829 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301830 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001831 adapter = pAdapterNode->adapter;
Jeff Johnson5287de52017-10-28 12:23:06 -07001832 scan_info = &adapter->scan_info;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001833
Sandeep Puligillaf8527122016-11-16 18:35:16 -08001834 if (sme_neighbor_middle_of_roaming
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001835 (hdd_ctx->hHal, adapter->sessionId)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001836 hdd_err("Roaming in progress, do not allow suspend");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001837 wlan_hdd_inc_suspend_stats(hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001838 SUSPEND_FAIL_ROAM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839 return -EAGAIN;
1840 }
1841
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001842 wlan_abort_scan(hdd_ctx->hdd_pdev, INVAL_PDEV_ID,
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001843 adapter->sessionId, INVALID_SCAN_ID, false);
Dustin Brownc86d5362017-07-07 13:08:51 -07001844
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001845 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, &pNext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001846 pAdapterNode = pNext;
1847 }
1848
Dustin Brown84411b02017-07-21 16:44:44 -07001849 /* flush any pending powersave timers */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001850 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Dustin Brown84411b02017-07-21 16:44:44 -07001851 while (pAdapterNode && QDF_IS_STATUS_SUCCESS(status)) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001852 adapter = pAdapterNode->adapter;
Dustin Brown84411b02017-07-21 16:44:44 -07001853
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001854 sme_ps_timer_flush_sync(hdd_ctx->hHal, adapter->sessionId);
Dustin Brown84411b02017-07-21 16:44:44 -07001855
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001856 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Dustin Brown84411b02017-07-21 16:44:44 -07001857 &pAdapterNode);
1858 }
1859
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001860 /*
1861 * Suspend IPA early before proceeding to suspend other entities like
1862 * firmware to avoid any race conditions.
1863 */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001864 if (hdd_ipa_suspend(hdd_ctx)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001865 hdd_err("IPA not ready to suspend!");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001866 wlan_hdd_inc_suspend_stats(hdd_ctx, SUSPEND_FAIL_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001867 return -EAGAIN;
1868 }
1869
Rajeev Kumareada0d02016-12-08 17:44:17 -08001870 /* Suspend control path scheduler */
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001871 scheduler_register_hdd_suspend_callback(hdd_suspend_cb);
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301872 scheduler_set_event_mask(MC_SUSPEND_EVENT);
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001873 scheduler_wake_up_controller_thread();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001874
Rajeev Kumareada0d02016-12-08 17:44:17 -08001875 /* Wait for suspend confirmation from scheduler */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001876 rc = wait_for_completion_timeout(&hdd_ctx->mc_sus_event_var,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877 msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
1878 if (!rc) {
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301879 scheduler_clear_event_mask(MC_SUSPEND_EVENT);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001880 hdd_err("Failed to stop mc thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881 goto resume_tx;
1882 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001883 hdd_ctx->is_scheduler_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001884
1885#ifdef QCA_CONFIG_SMP
1886 /* Suspend tlshim rx thread */
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301887 set_bit(RX_SUSPEND_EVENT, &cds_sched_context->ol_rx_event_flag);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001888 wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue);
1889 rc = wait_for_completion_timeout(&cds_sched_context->
1890 ol_suspend_rx_event,
1891 msecs_to_jiffies
1892 (RX_TLSHIM_SUSPEND_TIMEOUT));
1893 if (!rc) {
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301894 clear_bit(RX_SUSPEND_EVENT,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895 &cds_sched_context->ol_rx_event_flag);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001896 hdd_err("Failed to stop tl_shim rx thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001897 goto resume_all;
1898 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001899 hdd_ctx->is_ol_rx_thread_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900#endif
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301901 if (hdd_suspend_wlan() < 0)
1902 goto resume_all;
1903
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301904 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301905 TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001906 NO_SESSION, hdd_ctx->isWiphySuspended));
1907 hdd_ctx->isWiphySuspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001908
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001909 pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_NONE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001910
1911 EXIT();
1912 return 0;
1913
1914#ifdef QCA_CONFIG_SMP
1915resume_all:
1916
Rajeev Kumar0b732952016-12-08 17:51:39 -08001917 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001918 hdd_ctx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001919#endif
1920
1921resume_tx:
1922
1923 hdd_resume_wlan();
1924 return -ETIME;
1925
1926}
1927
1928/**
1929 * wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1930 * @wiphy: Pointer to wiphy
1931 * @wow: Pointer to wow
1932 *
1933 * This API is called when cfg80211 driver suspends
1934 *
1935 * Return: integer status
1936 */
1937int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1938 struct cfg80211_wowlan *wow)
1939{
1940 int ret;
1941
1942 cds_ssr_protect(__func__);
1943 ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
1944 cds_ssr_unprotect(__func__);
1945
1946 return ret;
1947}
1948
1949/**
Komal Seelama89be8d2016-09-29 11:09:26 +05301950 * hdd_stop_dhcp_ind() - API to stop DHCP sequence
1951 * @adapter: Adapter on which DHCP needs to be stopped
1952 *
1953 * Release the wakelock held for DHCP process and allow
1954 * the runtime pm to continue
1955 *
1956 * Return: None
1957 */
Jeff Johnson75b737d2017-08-29 14:24:41 -07001958static void hdd_stop_dhcp_ind(struct hdd_adapter *adapter)
Komal Seelama89be8d2016-09-29 11:09:26 +05301959{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001960 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Komal Seelama89be8d2016-09-29 11:09:26 +05301961
Srinivas Girigowdac06543c2017-03-09 15:10:03 -08001962 hdd_debug("DHCP stop indicated through power save");
Komal Seelama89be8d2016-09-29 11:09:26 +05301963 sme_dhcp_stop_ind(hdd_ctx->hHal, adapter->device_mode,
1964 adapter->macAddressCurrent.bytes,
1965 adapter->sessionId);
1966 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -08001967 qdf_runtime_pm_allow_suspend(&adapter->connect_rpm_ctx.connect);
Komal Seelama89be8d2016-09-29 11:09:26 +05301968}
1969
1970/**
1971 * hdd_start_dhcp_ind() - API to start DHCP sequence
1972 * @adapter: Adapter on which DHCP needs to be stopped
1973 *
1974 * Prevent APPS suspend and the runtime suspend during
1975 * DHCP sequence
1976 *
1977 * Return: None
1978 */
Jeff Johnson75b737d2017-08-29 14:24:41 -07001979static void hdd_start_dhcp_ind(struct hdd_adapter *adapter)
Komal Seelama89be8d2016-09-29 11:09:26 +05301980{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001981 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Komal Seelama89be8d2016-09-29 11:09:26 +05301982
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001983 hdd_debug("DHCP start indicated through power save");
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -08001984 qdf_runtime_pm_prevent_suspend(&adapter->connect_rpm_ctx.connect);
Dustin Brownceed67e2017-05-26 11:57:31 -07001985 hdd_prevent_suspend_timeout(HDD_WAKELOCK_TIMEOUT_CONNECT,
1986 WIFI_POWER_EVENT_WAKELOCK_DHCP);
Komal Seelama89be8d2016-09-29 11:09:26 +05301987 sme_dhcp_start_ind(hdd_ctx->hHal, adapter->device_mode,
1988 adapter->macAddressCurrent.bytes,
1989 adapter->sessionId);
1990}
1991
1992/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001993 * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
1994 * @wiphy: Pointer to wiphy
1995 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07001996 * @allow_power_save: is wlan allowed to go into power save mode
1997 * @timeout: Timeout value in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001998 *
1999 * Return: 0 for success, non-zero for failure
2000 */
2001static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07002002 struct net_device *dev,
2003 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002004 int timeout)
2005{
Jeff Johnsonf6d24282017-10-02 13:25:25 -07002006 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002007 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002008 int status;
2009
Dustin Brownecfce632016-09-13 10:41:45 -07002010 ENTER();
2011
Dustin Brownf660fb42016-09-09 12:04:00 -07002012 if (timeout < 0) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002013 hdd_debug("User space timeout: %d; Using default instead: %d",
Dustin Brownf660fb42016-09-09 12:04:00 -07002014 timeout, AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE);
2015 timeout = AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE;
2016 }
2017
Anurag Chouhan6d760662016-02-20 16:05:43 +05302018 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002019 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002020 return -EINVAL;
2021 }
2022
Jeff Johnsonf6d24282017-10-02 13:25:25 -07002023 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2024 hdd_err("invalid session id: %d", adapter->sessionId);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302025 return -EINVAL;
2026 }
2027
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302028 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002029 TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
Jeff Johnsonf6d24282017-10-02 13:25:25 -07002030 adapter->sessionId, timeout));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031
Jeff Johnsonf6d24282017-10-02 13:25:25 -07002032 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002033 status = wlan_hdd_validate_context(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002034
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302035 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002036 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002038 mutex_lock(&hdd_ctx->iface_change_lock);
2039 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2040 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002041 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05302042 return 0;
2043 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002044 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavalli99286452016-08-22 12:13:41 +05302045
Jeff Johnsonf6d24282017-10-02 13:25:25 -07002046 status = wlan_hdd_set_powersave(adapter, allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002047
Jeff Johnsonf6d24282017-10-02 13:25:25 -07002048 allow_power_save ? hdd_stop_dhcp_ind(adapter) :
2049 hdd_start_dhcp_ind(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002050
2051 EXIT();
2052 return status;
2053}
2054
2055/**
2056 * wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
2057 * @wiphy: Pointer to wiphy
2058 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07002059 * @allow_power_save: is wlan allowed to go into power save mode
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002060 * @timeout: Timeout value
2061 *
2062 * Return: 0 for success, non-zero for failure
2063 */
2064int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07002065 struct net_device *dev,
2066 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002067 int timeout)
2068{
2069 int ret;
2070
2071 cds_ssr_protect(__func__);
Dustin Brownf660fb42016-09-09 12:04:00 -07002072 ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev,
2073 allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002074 cds_ssr_unprotect(__func__);
2075
2076 return ret;
2077}
2078
2079/**
2080 * __wlan_hdd_cfg80211_set_txpower() - set TX power
2081 * @wiphy: Pointer to wiphy
2082 * @wdev: Pointer to network device
2083 * @type: TX power setting type
2084 * @dbm: TX power in dbm
2085 *
2086 * Return: 0 for success, non-zero for failure
2087 */
2088static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002089 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002090 enum nl80211_tx_power_setting type,
2091 int dbm)
2092{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002093 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002094 tHalHandle hHal = NULL;
Anurag Chouhan6d760662016-02-20 16:05:43 +05302095 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
2096 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002097 int status;
2098
2099 ENTER();
2100
Anurag Chouhan6d760662016-02-20 16:05:43 +05302101 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002102 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002103 return -EINVAL;
2104 }
2105
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302106 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002107 TRACE_CODE_HDD_CFG80211_SET_TXPOWER,
2108 NO_SESSION, type));
2109
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002110 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302111 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002112 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002113
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002114 hHal = hdd_ctx->hHal;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002115
2116 if (0 != sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, dbm)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002117 hdd_err("sme_cfg_set_int failed for tx power %hu",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002118 dbm);
2119 return -EIO;
2120 }
2121
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002122 hdd_debug("Set tx power level %d dbm", dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002123
2124 switch (type) {
2125 /* Automatically determine transmit power */
2126 case NL80211_TX_POWER_AUTOMATIC:
2127 /* Fall through */
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05302128 case NL80211_TX_POWER_LIMITED:
2129 /* Limit TX power by the mBm parameter */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002130 if (sme_set_max_tx_power(hHal, bssid, selfMac, dbm) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302131 QDF_STATUS_SUCCESS) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002132 hdd_err("Setting maximum tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002133 return -EIO;
2134 }
2135 break;
2136
2137 case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */
Jeff Johnsonc3273322016-07-06 15:28:17 -07002138 hdd_err("NL80211_TX_POWER_FIXED not supported");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002139 return -EOPNOTSUPP;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002140
2141 default:
Jeff Johnsonc3273322016-07-06 15:28:17 -07002142 hdd_err("Invalid power setting type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002143 return -EIO;
2144 }
2145
2146 EXIT();
2147 return 0;
2148}
2149
2150/**
2151 * wlan_hdd_cfg80211_set_txpower() - set TX power
2152 * @wiphy: Pointer to wiphy
2153 * @wdev: Pointer to network device
2154 * @type: TX power setting type
2155 * @dbm: TX power in dbm
2156 *
2157 * Return: 0 for success, non-zero for failure
2158 */
2159int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002160 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002161 enum nl80211_tx_power_setting type,
2162 int dbm)
2163{
2164 int ret;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05302165
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002166 cds_ssr_protect(__func__);
2167 ret = __wlan_hdd_cfg80211_set_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002168 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002169 type, dbm);
2170 cds_ssr_unprotect(__func__);
2171
2172 return ret;
2173}
2174
2175/**
2176 * __wlan_hdd_cfg80211_get_txpower() - get TX power
2177 * @wiphy: Pointer to wiphy
2178 * @wdev: Pointer to network device
2179 * @dbm: Pointer to TX power in dbm
2180 *
2181 * Return: 0 for success, non-zero for failure
2182 */
2183static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002184 struct wireless_dev *wdev,
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002185 int *dbm)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002186{
2187
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002188 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002189 struct net_device *ndev = wdev->netdev;
Jeff Johnson75b737d2017-08-29 14:24:41 -07002190 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002191 int status;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07002192 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002193
2194 ENTER();
2195
Anurag Chouhan6d760662016-02-20 16:05:43 +05302196 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002197 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002198 return -EINVAL;
2199 }
2200
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002201 status = wlan_hdd_validate_context(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002202 if (0 != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002203 *dbm = 0;
2204 return status;
2205 }
2206
Arun Khandavalli99286452016-08-22 12:13:41 +05302207 /* Validate adapter sessionId */
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302208 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2209 hdd_err("invalid session id: %d", adapter->sessionId);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002210 return -EINVAL;
Arun Khandavalli99286452016-08-22 12:13:41 +05302211 }
2212
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002213 mutex_lock(&hdd_ctx->iface_change_lock);
2214 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2215 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002216 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05302217 /* Send cached data to upperlayer*/
Jeff Johnson861dd4f2017-10-24 10:10:40 -07002218 *dbm = adapter->hdd_stats.class_a_stat.max_pwr;
Arun Khandavalli99286452016-08-22 12:13:41 +05302219 return 0;
2220 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002221 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavalli99286452016-08-22 12:13:41 +05302222
Ganesh Kondabattinif847f062017-05-26 12:36:24 +05302223 if (sta_ctx->conn_info.connState != eConnectionState_Associated) {
2224 hdd_debug("Not associated");
2225 /*To keep GUI happy */
2226 *dbm = 0;
2227 return 0;
2228 }
2229
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302230 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302231 TRACE_CODE_HDD_CFG80211_GET_TXPOWER,
Arun Khandavalli99286452016-08-22 12:13:41 +05302232 adapter->sessionId, adapter->device_mode));
2233 wlan_hdd_get_class_astats(adapter);
Jeff Johnson861dd4f2017-10-24 10:10:40 -07002234 *dbm = adapter->hdd_stats.class_a_stat.max_pwr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002235
2236 EXIT();
2237 return 0;
2238}
2239
2240/**
2241 * wlan_hdd_cfg80211_get_txpower() - cfg80211 get power handler function
2242 * @wiphy: Pointer to wiphy structure.
2243 * @wdev: Pointer to wireless_dev structure.
2244 * @dbm: dbm
2245 *
2246 * This is the cfg80211 get txpower handler function which invokes
2247 * the internal function @__wlan_hdd_cfg80211_get_txpower with
2248 * SSR protection.
2249 *
2250 * Return: 0 for success, error number on failure.
2251 */
2252int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002253 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002254 int *dbm)
2255{
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002256 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002257
2258 cds_ssr_protect(__func__);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002259 ret = __wlan_hdd_cfg80211_get_txpower(wiphy, wdev, dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002260 cds_ssr_unprotect(__func__);
2261
2262 return ret;
2263}
Kapil Gupta6213c012016-09-02 19:39:09 +05302264
Jeff Johnson4fbee2f2017-10-03 11:19:35 -07002265int hdd_set_qpower_config(struct hdd_context *hddctx,
2266 struct hdd_adapter *adapter,
Dustin Brown10a7b712016-10-07 10:31:16 -07002267 u8 qpower)
Kapil Gupta6213c012016-09-02 19:39:09 +05302268{
Dustin Brown10a7b712016-10-07 10:31:16 -07002269 QDF_STATUS status;
Kapil Gupta6213c012016-09-02 19:39:09 +05302270
2271 if (!hddctx->config->enablePowersaveOffload) {
2272 hdd_err("qpower is disabled in configuration");
2273 return -EINVAL;
2274 }
Manjeet Singh91b7bb82017-02-10 18:35:40 +05302275 if (adapter->device_mode != QDF_STA_MODE &&
2276 adapter->device_mode != QDF_P2P_CLIENT_MODE) {
2277 hdd_info(FL("QPOWER only allowed in STA/P2P-Client modes:%d "),
2278 adapter->device_mode);
2279 return -EINVAL;
2280 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002281
Kapil Gupta6213c012016-09-02 19:39:09 +05302282 if (qpower > PS_DUTY_CYCLING_QPOWER ||
2283 qpower < PS_LEGACY_NODEEPSLEEP) {
Dustin Brown10a7b712016-10-07 10:31:16 -07002284 hdd_err("invalid qpower value: %d", qpower);
Kapil Gupta6213c012016-09-02 19:39:09 +05302285 return -EINVAL;
2286 }
Kapil Gupta6213c012016-09-02 19:39:09 +05302287
Kiran Kumar Lokere7006e0a2017-03-07 19:28:36 -08002288 if (hddctx->config->nMaxPsPoll) {
2289 if ((qpower == PS_QPOWER_NODEEPSLEEP) ||
2290 (qpower == PS_LEGACY_NODEEPSLEEP))
2291 qpower = PS_LEGACY_NODEEPSLEEP;
2292 else
2293 qpower = PS_LEGACY_DEEPSLEEP;
2294 hdd_info("Qpower disabled, %d", qpower);
2295 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002296 status = wma_set_qpower_config(adapter->sessionId, qpower);
2297 if (status != QDF_STATUS_SUCCESS) {
2298 hdd_err("failed to configure qpower: %d", status);
2299 return -EINVAL;
Kapil Gupta6213c012016-09-02 19:39:09 +05302300 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002301
Kapil Gupta6213c012016-09-02 19:39:09 +05302302 return 0;
2303}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002304
Dustin Brown54096432017-02-23 13:00:44 -08002305
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002306#ifdef WLAN_SUSPEND_RESUME_TEST
Dustin Brownbc81a472016-10-26 16:56:59 -07002307static struct net_device *g_dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002308static struct wiphy *g_wiphy;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002309static enum wow_resume_trigger g_resume_trigger;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002310
2311#define HDD_FA_SUSPENDED_BIT (0)
2312static unsigned long fake_apps_state;
2313
Dustin Brownd53d1a82016-10-03 12:57:33 -07002314/**
2315 * __hdd_wlan_fake_apps_resume() - The core logic for
2316 * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(),
2317 * which is only need for non-irq resume
Dustin Brownbc81a472016-10-26 16:56:59 -07002318 * @wiphy: the kernel wiphy struct for the device being resumed
2319 * @dev: the kernel net_device struct for the device being resumed
Dustin Brownd53d1a82016-10-03 12:57:33 -07002320 *
Dustin Brownbc81a472016-10-26 16:56:59 -07002321 * Return: none, calls QDF_BUG() on failure
Dustin Brownd53d1a82016-10-03 12:57:33 -07002322 */
Dustin Brownbc81a472016-10-26 16:56:59 -07002323static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy,
2324 struct net_device *dev)
Dustin Brownd53d1a82016-10-03 12:57:33 -07002325{
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002326 struct hif_opaque_softc *hif_ctx;
Dustin Brownddb59702017-01-12 16:20:31 -08002327 qdf_device_t qdf_dev;
Dustin Brownd53d1a82016-10-03 12:57:33 -07002328
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002329 hdd_info("Unit-test resume WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002330
2331 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2332 if (!qdf_dev) {
2333 hdd_err("Failed to get QDF device context");
2334 QDF_BUG(0);
2335 return;
2336 }
2337
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002338 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2339 if (!hif_ctx) {
2340 hdd_err("Failed to get HIF context");
2341 return;
2342 }
2343
Dustin Brownd53d1a82016-10-03 12:57:33 -07002344 if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002345 hdd_alert("Not unit-test suspended; Nothing to do");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002346 return;
2347 }
2348
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002349 /* simulate kernel disable irqs */
2350 QDF_BUG(!hif_apps_wake_irq_disable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002351
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002352 QDF_BUG(!wlan_hdd_bus_resume_noirq());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002353
2354 /* simulate kernel enable irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002355 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002356
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002357 QDF_BUG(!wlan_hdd_bus_resume());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002358
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002359 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
2360
2361 if (g_resume_trigger == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2362 hif_vote_link_down(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002363
2364 dev->watchdog_timeo = HDD_TX_TIMEOUT;
Dustin Brown562b9672016-12-22 15:25:33 -08002365
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002366 hdd_alert("Unit-test resume succeeded");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002367}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002368
2369/**
2370 * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming
2371 * from unit-test initiated suspend from irq wakeup signal
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002372 *
2373 * Resume wlan after getting very 1st CE interrupt from target
2374 *
2375 * Return: none
2376 */
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002377static void hdd_wlan_fake_apps_resume_irq_callback(void)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002378{
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002379 hdd_info("Trigger unit-test resume WLAN");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002380
2381 QDF_BUG(g_wiphy);
Dustin Brownbc81a472016-10-26 16:56:59 -07002382 QDF_BUG(g_dev);
2383 __hdd_wlan_fake_apps_resume(g_wiphy, g_dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002384 g_wiphy = NULL;
Dustin Brownbc81a472016-10-26 16:56:59 -07002385 g_dev = NULL;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002386}
2387
Dustin Brown54096432017-02-23 13:00:44 -08002388int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev,
2389 enum wow_interface_pause pause_setting,
2390 enum wow_resume_trigger resume_setting)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002391{
Dustin Brownddb59702017-01-12 16:20:31 -08002392 qdf_device_t qdf_dev;
2393 struct hif_opaque_softc *hif_ctx;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002394 int errno;
Dustin Brown54096432017-02-23 13:00:44 -08002395 struct wow_enable_params wow_params = {
2396 .is_unit_test = true,
2397 .interface_pause = pause_setting,
2398 .resume_trigger = resume_setting
2399 };
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002400
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002401 hdd_info("Unit-test suspend WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002402
Dustin Brown54096432017-02-23 13:00:44 -08002403 if (pause_setting < WOW_INTERFACE_PAUSE_DEFAULT ||
2404 pause_setting >= WOW_INTERFACE_PAUSE_COUNT) {
2405 hdd_err("Invalid interface pause %d (expected range [0, 2])",
2406 pause_setting);
2407 return -EINVAL;
2408 }
2409
2410 if (resume_setting < WOW_RESUME_TRIGGER_DEFAULT ||
2411 resume_setting >= WOW_RESUME_TRIGGER_COUNT) {
2412 hdd_err("Invalid resume trigger %d (expected range [0, 2])",
2413 resume_setting);
2414 return -EINVAL;
2415 }
2416
Dustin Brownddb59702017-01-12 16:20:31 -08002417 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2418 if (!qdf_dev) {
2419 hdd_err("Failed to get QDF device context");
2420 return -EINVAL;
2421 }
2422
2423 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2424 if (!hif_ctx) {
2425 hdd_err("Failed to get HIF context");
2426 return -EINVAL;
2427 }
2428
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002429 if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002430 hdd_alert("Already unit-test suspended; Nothing to do");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002431 return 0;
2432 }
2433
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002434 /* pci link is needed to wakeup from HTC wakeup trigger */
2435 if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2436 hif_vote_link_up(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002437
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002438 errno = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL);
2439 if (errno)
2440 goto link_down;
2441
2442 errno = wlan_hdd_unit_test_bus_suspend(wow_params);
2443 if (errno)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002444 goto cfg80211_resume;
2445
2446 /* simulate kernel disabling irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002447 errno = hif_apps_irqs_disable(hif_ctx);
2448 if (errno)
2449 goto bus_resume;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002450
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002451 errno = wlan_hdd_bus_suspend_noirq();
2452 if (errno)
2453 goto enable_irqs;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002454
Dustin Brownbc81a472016-10-26 16:56:59 -07002455 /* pass wiphy/dev to callback via global variables */
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002456 g_wiphy = wiphy;
Dustin Brownbc81a472016-10-26 16:56:59 -07002457 g_dev = dev;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002458 g_resume_trigger = resume_setting;
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002459 hif_ut_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002460
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002461 /* re-enable wake irq */
2462 errno = hif_apps_wake_irq_enable(hif_ctx);
2463 if (errno)
2464 goto fake_apps_resume;
2465
Dustin Brownbc81a472016-10-26 16:56:59 -07002466 /*
2467 * Tell the kernel not to worry if TX queues aren't moving. This is
2468 * expected since we are suspending the wifi hardware, but not APPS
2469 */
2470 dev->watchdog_timeo = INT_MAX;
2471
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002472 hdd_alert("Unit-test suspend succeeded");
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002473
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002474 return 0;
2475
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002476fake_apps_resume:
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002477 hif_ut_apps_resume(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002478
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002479enable_irqs:
2480 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
2481
2482bus_resume:
2483 QDF_BUG(!wlan_hdd_bus_resume());
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002484
2485cfg80211_resume:
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002486 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002487
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002488link_down:
2489 hif_vote_link_down(hif_ctx);
2490
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002491 clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state);
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002492 hdd_err("Unit-test suspend failed: %d", errno);
2493
2494 return errno;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002495}
2496
Dustin Brownbc81a472016-10-26 16:56:59 -07002497int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002498{
Dustin Brownddb59702017-01-12 16:20:31 -08002499 struct hif_opaque_softc *hif_ctx;
2500
2501 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2502 if (!hif_ctx) {
2503 hdd_err("Failed to get HIF context");
2504 return -EINVAL;
2505 }
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002506
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002507 hif_ut_apps_resume(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002508 __hdd_wlan_fake_apps_resume(wiphy, dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002509
2510 return 0;
2511}
2512#endif