blob: f86260d0d8005f01c789f502a0bb7b0d45c3ceee [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"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080084
85/* Preprocessor definitions and constants */
Yue Ma5fe30dd2017-05-02 15:47:40 -070086#ifdef QCA_WIFI_NAPIER_EMULATION
87#define HDD_SSR_BRING_UP_TIME 3000000
88#else
Yue Ma4ea4f052015-10-27 12:25:27 -070089#define HDD_SSR_BRING_UP_TIME 30000
Yue Ma5fe30dd2017-05-02 15:47:40 -070090#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080091
92/* Type declarations */
93
Abhishek Singhbaea27d2016-04-27 13:29:30 +053094#ifdef FEATURE_WLAN_DIAG_SUPPORT
95/**
96 * hdd_wlan_suspend_resume_event()- send suspend/resume state
97 * @state: suspend/resume state
98 *
99 * This Function send send suspend resume state diag event
100 *
101 * Return: void.
102 */
103void hdd_wlan_suspend_resume_event(uint8_t state)
104{
105 WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend);
106 qdf_mem_zero(&suspend_state, sizeof(suspend_state));
107
108 suspend_state.state = state;
109 WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
110}
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530111
112/**
113 * hdd_wlan_offload_event()- send offloads event
114 * @type: offload type
115 * @state: enabled or disabled
116 *
117 * This Function send offloads enable/disable diag event
118 *
119 * Return: void.
120 */
121
122void hdd_wlan_offload_event(uint8_t type, uint8_t state)
123{
124 WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req);
125 qdf_mem_zero(&host_offload, sizeof(host_offload));
126
127 host_offload.offload_type = type;
128 host_offload.state = state;
129
130 WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ);
131}
Abhishek Singhbaea27d2016-04-27 13:29:30 +0530132#endif
133
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800134/* Function and variables declarations */
135
136extern struct notifier_block hdd_netdev_notifier;
137
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800138/**
Mukul Sharma3d36c392017-01-18 18:39:12 +0530139 * hdd_enable_gtk_offload() - enable GTK offload
140 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800141 *
Mukul Sharma3d36c392017-01-18 18:39:12 +0530142 * Central function to enable GTK offload.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800143 *
144 * Return: nothing
145 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700146static void hdd_enable_gtk_offload(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800147{
Mukul Sharma3d36c392017-01-18 18:39:12 +0530148 QDF_STATUS status;
149 status = pmo_ucfg_enable_gtk_offload_in_fwr(adapter->hdd_vdev);
150 if (status != QDF_STATUS_SUCCESS)
151 hdd_info("Failed to enable gtk offload");
152}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800153
Mukul Sharma3d36c392017-01-18 18:39:12 +0530154/**
155 * hdd_disable_gtk_offload() - disable GTK offload
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700156 * @adapter: pointer to the adapter
Mukul Sharma3d36c392017-01-18 18:39:12 +0530157 *
158 * Central function to disable GTK offload.
159 *
160 * Return: nothing
161 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700162static void hdd_disable_gtk_offload(struct hdd_adapter *adapter)
Mukul Sharma3d36c392017-01-18 18:39:12 +0530163{
164 struct pmo_gtk_rsp_req gtk_rsp_request;
165 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800166
Mukul Sharma3d36c392017-01-18 18:39:12 +0530167 /* ensure to get gtk rsp first before disable it*/
168 gtk_rsp_request.callback =
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530169 wlan_hdd_cfg80211_update_replay_counter_cb;
Mukul Sharma3d36c392017-01-18 18:39:12 +0530170 /* Passing as void* as PMO does not know legacy HDD adapter type */
171 gtk_rsp_request.callback_context =
172 (void *)adapter;
173 status = pmo_ucfg_get_gtk_rsp(adapter->hdd_vdev,
174 &gtk_rsp_request);
175 if (status != QDF_STATUS_SUCCESS) {
176 hdd_err("Failed to send get gtk rsp status:%d", status);
177 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800178 }
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800179 hdd_debug("send get_gtk_rsp successful");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530180 status = pmo_ucfg_disable_gtk_offload_in_fwr(adapter->hdd_vdev);
181 if (status != QDF_STATUS_SUCCESS)
182 hdd_info("Failed to disable gtk offload");
183
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530186
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800187/**
188 * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function
189 * @nb: notifier block that was registered with the kernel
190 * @data: (unused) generic data that was registered with the kernel
191 * @arg: (unused) generic argument that was registered with the kernel
192 *
193 * This is a callback function that is registered with the kernel via
194 * register_inet6addr_notifier() which allows the driver to be
195 * notified when there is an IPv6 address change.
196 *
197 * Return: NOTIFY_DONE to indicate we don't care what happens with
198 * other callbacks
199 */
200static int __wlan_hdd_ipv6_changed(struct notifier_block *nb,
Dustin Brownf13b8c32017-05-19 17:23:08 -0700201 unsigned long data, void *arg)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800202{
203 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
204 struct net_device *ndev = ifa->idev->dev;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700205 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700206 struct hdd_context *hdd_ctx;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700207 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800208
Jeff Johnson158c8d02016-10-31 13:11:48 -0700209 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530210
Dustin Brownf13b8c32017-05-19 17:23:08 -0700211 errno = hdd_validate_adapter(adapter);
212 if (errno)
213 goto exit;
214
215 if (adapter->dev == ndev &&
216 (adapter->device_mode == QDF_STA_MODE ||
217 adapter->device_mode == QDF_P2P_CLIENT_MODE ||
218 adapter->device_mode == QDF_NDI_MODE)) {
219 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
220 errno = wlan_hdd_validate_context(hdd_ctx);
221 if (errno)
222 goto exit;
223
Nachiket Kukadec9045fe2017-06-19 15:14:43 +0530224 /* Ignore if the interface is down */
225 if (!(ndev->flags & IFF_UP)) {
226 hdd_err("Rcvd change addr request on %s(flags 0x%X)",
227 ndev->name, ndev->flags);
228 hdd_err("NETDEV Interface is down, ignoring...");
229 goto exit;
230 }
231
Dustin Brownf13b8c32017-05-19 17:23:08 -0700232 hdd_debug("invoking sme_dhcp_done_ind");
233 sme_dhcp_done_ind(hdd_ctx->hHal, adapter->sessionId);
234 schedule_work(&adapter->ipv6NotifierWorkQueue);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800235 }
236
Dustin Brownf13b8c32017-05-19 17:23:08 -0700237exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530238 EXIT();
Dustin Brownf13b8c32017-05-19 17:23:08 -0700239
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800240 return NOTIFY_DONE;
241}
242
243/**
244 * wlan_hdd_ipv6_changed() - IPv6 change notifier callback
245 * @nb: pointer to notifier block
246 * @data: data
247 * @arg: arg
248 *
249 * This is the IPv6 notifier callback function gets invoked
250 * if any change in IP and then invoke the function @__wlan_hdd_ipv6_changed
251 * to reconfigure the offload parameters.
252 *
253 * Return: 0 on success, error number otherwise.
254 */
255int wlan_hdd_ipv6_changed(struct notifier_block *nb,
256 unsigned long data, void *arg)
257{
258 int ret;
259
260 cds_ssr_protect(__func__);
261 ret = __wlan_hdd_ipv6_changed(nb, data, arg);
262 cds_ssr_unprotect(__func__);
263
264 return ret;
265}
266
267/**
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530268 * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses
269 * @idev: pointer to net device
270 * @ipv6addr: destination array to fill IPv6 addresses
271 * @ipv6addr_type: IPv6 Address type
272 * @count: number of IPv6 addresses
273 *
274 * This is the IPv6 utility function to populate unicast addresses.
275 *
276 * Return: 0 on success, error number otherwise.
277 */
278static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
279 uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN],
280 uint8_t *ipv6addr_type, uint32_t *count)
281{
282 struct inet6_ifaddr *ifa;
283 struct list_head *p;
284 uint32_t scope;
285
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700286 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530287 list_for_each(p, &idev->addr_list) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530288 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700289 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530290 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700291 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530292 ifa = list_entry(p, struct inet6_ifaddr, if_list);
293 if (ifa->flags & IFA_F_DADFAILED)
294 continue;
295 scope = ipv6_addr_src_scope(&ifa->addr);
296 switch (scope) {
297 case IPV6_ADDR_SCOPE_GLOBAL:
298 case IPV6_ADDR_SCOPE_LINKLOCAL:
299 qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
300 sizeof(ifa->addr.s6_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530301 ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE;
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800302 hdd_debug("Index %d scope = %s UC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530303 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
304 "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
305 *count += 1;
306 break;
307 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800308 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530309 }
310 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700311
312 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530313 return 0;
314}
315
316/**
317 * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses
318 * @idev: pointer to net device
319 * @ipv6addr: destination array to fill IPv6 addresses
320 * @ipv6addr_type: IPv6 Address type
321 * @count: number of IPv6 addresses
322 *
323 * This is the IPv6 utility function to populate anycast addresses.
324 *
325 * Return: 0 on success, error number otherwise.
326 */
327static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
328 uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN],
329 uint8_t *ipv6addr_type, uint32_t *count)
330{
331 struct ifacaddr6 *ifaca;
332 uint32_t scope;
333
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700334 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530335 for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530336 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700337 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530338 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700339 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530340 /* For anycast addr no DAD */
341 scope = ipv6_addr_src_scope(&ifaca->aca_addr);
342 switch (scope) {
343 case IPV6_ADDR_SCOPE_GLOBAL:
344 case IPV6_ADDR_SCOPE_LINKLOCAL:
345 qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
346 sizeof(ifaca->aca_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530347 ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE;
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800348 hdd_debug("Index %d scope = %s AC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530349 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
350 "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
351 *count += 1;
352 break;
353 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800354 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530355 }
356 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700357
358 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530359 return 0;
360}
361
Jeff Johnson75b737d2017-08-29 14:24:41 -0700362void hdd_enable_ns_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530363 enum pmo_offload_trigger trigger)
Dustin Brown2444ee62016-09-06 17:20:36 -0700364{
365 struct inet6_dev *in6_dev;
Dustin Brown2444ee62016-09-06 17:20:36 -0700366 QDF_STATUS status;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700367 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530368 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
369 struct pmo_ns_req *ns_req = NULL;
370 int err;
371
372 ENTER();
373 if (!psoc) {
374 hdd_err("psoc is NULL");
375 goto out;
376 }
Dustin Brown2444ee62016-09-06 17:20:36 -0700377
378 in6_dev = __in6_dev_get(adapter->dev);
379 if (NULL == in6_dev) {
380 hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530381 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700382 }
383
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530384 ns_req = qdf_mem_malloc(sizeof(*ns_req));
385 if (!ns_req) {
386 hdd_err("fail to allocate ns_req");
387 goto out;
388 }
389
390 ns_req->psoc = psoc;
391 ns_req->vdev_id = adapter->sessionId;
392 ns_req->trigger = trigger;
393 ns_req->count = 0;
394
Dustin Brown2444ee62016-09-06 17:20:36 -0700395 /* Unicast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530396 err = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
397 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700398 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530399 hdd_disable_ns_offload(adapter, trigger);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530400 hdd_debug("Max supported addresses: disabling NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530401 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700402 }
403
404 /* Anycast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530405 err = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
406 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700407 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530408 hdd_disable_ns_offload(adapter, trigger);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530409 hdd_debug("Max supported addresses: disabling NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530410 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700411 }
412
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530413 /* cache ns request */
414 status = pmo_ucfg_cache_ns_offload_req(ns_req);
415 if (status != QDF_STATUS_SUCCESS) {
416 hdd_err("Failed to cache ns request status: %d", status);
417 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700418 }
419
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530420 /* enable ns request */
421 status = pmo_ucfg_enable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
422 if (status != QDF_STATUS_SUCCESS)
Dustin Brown2444ee62016-09-06 17:20:36 -0700423 hdd_err("Failed to enable HostOffload feature with status: %d",
424 status);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530425 else
426 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
427out:
428 if (ns_req)
429 qdf_mem_free(ns_req);
430 EXIT();
431
Dustin Brown2444ee62016-09-06 17:20:36 -0700432}
433
Jeff Johnson75b737d2017-08-29 14:24:41 -0700434void hdd_disable_ns_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530435 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800436{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530437 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800438
439 ENTER();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530440 status = pmo_ucfg_flush_ns_offload_req(adapter->hdd_vdev);
441 if (status != QDF_STATUS_SUCCESS) {
442 hdd_err("Failed to flush NS Offload");
443 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800444 }
445
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530446 status = pmo_ucfg_disable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
447 if (status != QDF_STATUS_SUCCESS)
448 hdd_err("Failed to disable NS Offload");
Dustin Brown2444ee62016-09-06 17:20:36 -0700449 else
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530450 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD,
451 SIR_OFFLOAD_DISABLE);
452out:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800453 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530454
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800455}
456
457/**
458 * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function
459 * @work: registered work item
460 *
461 * This function performs the work initially trigged by a callback
462 * from the IPv6 netdev notifier. Since this means there has been a
463 * change in IPv6 state for the interface, the NS offload is
464 * reconfigured.
465 *
466 * Return: None
467 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700468static void __hdd_ipv6_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800469{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700470 struct hdd_context *hdd_ctx;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700471 struct hdd_adapter *adapter;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700472 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800473
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530474 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800475
Jeff Johnson75b737d2017-08-29 14:24:41 -0700476 adapter = container_of(work, struct hdd_adapter, ipv6NotifierWorkQueue);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700477 errno = hdd_validate_adapter(adapter);
478 if (errno)
479 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800480
Dustin Brownf13b8c32017-05-19 17:23:08 -0700481 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
482 errno = wlan_hdd_validate_context(hdd_ctx);
483 if (errno)
484 goto exit;
485
486 hdd_enable_ns_offload(adapter, pmo_ipv6_change_notify);
487
488exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530489 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800490}
491
492/**
493 * hdd_ipv6_notifier_work_queue() - IP V6 change notifier work handler
494 * @work: Pointer to work context
495 *
496 * Return: none
497 */
498void hdd_ipv6_notifier_work_queue(struct work_struct *work)
499{
500 cds_ssr_protect(__func__);
501 __hdd_ipv6_notifier_work_queue(work);
502 cds_ssr_unprotect(__func__);
503}
504
Jeff Johnson75b737d2017-08-29 14:24:41 -0700505static void hdd_enable_hw_filter(struct hdd_adapter *adapter)
Dustin Brown1224e212017-05-12 14:02:12 -0700506{
507 QDF_STATUS status;
508
509 ENTER();
510
511 status = pmo_ucfg_enable_hw_filter_in_fwr(adapter->hdd_vdev);
512 if (status != QDF_STATUS_SUCCESS)
513 hdd_info("Failed to enable hardware filter");
514
515 EXIT();
516}
517
Jeff Johnson75b737d2017-08-29 14:24:41 -0700518static void hdd_disable_hw_filter(struct hdd_adapter *adapter)
Dustin Brown1224e212017-05-12 14:02:12 -0700519{
520 QDF_STATUS status;
521
522 ENTER();
523
524 status = pmo_ucfg_disable_hw_filter_in_fwr(adapter->hdd_vdev);
525 if (status != QDF_STATUS_SUCCESS)
526 hdd_info("Failed to disable hardware filter");
527
528 EXIT();
529}
530
Jeff Johnson75b737d2017-08-29 14:24:41 -0700531void hdd_enable_host_offloads(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530532 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800533{
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530534 ENTER();
535
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530536 if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
537 hdd_info("offload is not supported on this vdev opmode: %d",
538 adapter->device_mode);
539 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800540 }
541
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530542 if (!pmo_ucfg_is_vdev_connected(adapter->hdd_vdev)) {
543 hdd_info("vdev is not connected");
544 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800545 }
546
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530547 hdd_info("enable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530548 hdd_enable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530549 hdd_enable_arp_offload(adapter, trigger);
550 hdd_enable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530551 hdd_enable_mc_addr_filtering(adapter, trigger);
Dustin Brown1224e212017-05-12 14:02:12 -0700552 hdd_enable_hw_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530553out:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530554 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530555
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800556}
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530557
Jeff Johnson75b737d2017-08-29 14:24:41 -0700558void hdd_disable_host_offloads(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530559 enum pmo_offload_trigger trigger)
560{
561 ENTER();
562
563 if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
564 hdd_info("offload is not supported on this vdev opmode: %d",
565 adapter->device_mode);
566 goto out;
567 }
568
569 if (!pmo_ucfg_is_vdev_connected(adapter->hdd_vdev)) {
570 hdd_info("vdev is not connected");
571 goto out;
572 }
573
574 hdd_info("disable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530575 hdd_disable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530576 hdd_disable_arp_offload(adapter, trigger);
577 hdd_disable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530578 hdd_disable_mc_addr_filtering(adapter, trigger);
Dustin Brown1224e212017-05-12 14:02:12 -0700579 hdd_disable_hw_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530580out:
581 EXIT();
582
583}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800584
585/**
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800586 * hdd_lookup_ifaddr() - Lookup interface address data by name
587 * @adapter: the adapter whose name should be searched for
588 *
589 * return in_ifaddr pointer on success, NULL for failure
590 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700591static struct in_ifaddr *hdd_lookup_ifaddr(struct hdd_adapter *adapter)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800592{
593 struct in_ifaddr *ifa;
594 struct in_device *in_dev;
595
596 if (!adapter) {
597 hdd_err("adapter is null");
598 return NULL;
599 }
600
601 in_dev = __in_dev_get_rtnl(adapter->dev);
602 if (!in_dev) {
603 hdd_err("Failed to get in_device");
604 return NULL;
605 }
606
607 /* lookup address data by interface name */
608 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
609 if (!strcmp(adapter->dev->name, ifa->ifa_label))
610 return ifa;
611 }
612
613 return NULL;
614}
615
616/**
617 * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address
618 * @adapter: the adapter whose IPv4 address is desired
619 * @ipv4_addr: the address of the array to copy the IPv4 address into
620 *
621 * return: zero for success; non-zero for failure
622 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700623static int hdd_populate_ipv4_addr(struct hdd_adapter *adapter, uint8_t *ipv4_addr)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800624{
625 struct in_ifaddr *ifa;
626 int i;
627
628 if (!adapter) {
629 hdd_err("adapter is null");
630 return -EINVAL;
631 }
632
633 if (!ipv4_addr) {
634 hdd_err("ipv4_addr is null");
635 return -EINVAL;
636 }
637
638 ifa = hdd_lookup_ifaddr(adapter);
639 if (!ifa || !ifa->ifa_local) {
640 hdd_err("ipv4 address not found");
641 return -EINVAL;
642 }
643
644 /* convert u32 to byte array */
645 for (i = 0; i < 4; i++)
646 ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff;
647
648 return 0;
649}
650
651/**
652 * hdd_set_grat_arp_keepalive() - Enable grat APR keepalive
653 * @adapter: the HDD adapter to configure
654 *
655 * This configures gratuitous APR keepalive based on the adapter's current
656 * connection information, specifically IPv4 address and BSSID
657 *
658 * return: zero for success, non-zero for failure
659 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700660static int hdd_set_grat_arp_keepalive(struct hdd_adapter *adapter)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800661{
662 QDF_STATUS status;
663 int exit_code;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700664 struct hdd_context *hdd_ctx;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700665 struct hdd_station_ctx *sta_ctx;
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800666 tSirKeepAliveReq req = {
667 .packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP,
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800668 .dest_macaddr = QDF_MAC_ADDR_BROADCAST_INITIALIZER,
669 };
670
671 if (!adapter) {
672 hdd_err("adapter is null");
673 return -EINVAL;
674 }
675
676 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
677 if (!hdd_ctx) {
678 hdd_err("hdd_ctx is null");
679 return -EINVAL;
680 }
681
682 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
683 if (!sta_ctx) {
684 hdd_err("sta_ctx is null");
685 return -EINVAL;
686 }
687
688 exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr);
689 if (exit_code) {
690 hdd_err("Failed to populate ipv4 address");
691 return exit_code;
692 }
693
Dustin Brown6b4643d2017-02-09 12:19:28 -0800694 /* according to RFC5227, sender/target ip address should be the same */
695 qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr,
696 sizeof(req.destIpv4Addr));
697
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800698 qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssId);
699 req.timePeriod = hdd_ctx->config->infraStaKeepAlivePeriod;
700 req.sessionId = adapter->sessionId;
701
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800702 hdd_debug("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u",
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800703 req.hostIpv4Addr[0], req.hostIpv4Addr[1],
704 req.hostIpv4Addr[2], req.hostIpv4Addr[3]);
705
706 status = sme_set_keep_alive(hdd_ctx->hHal, req.sessionId, &req);
707 if (QDF_IS_STATUS_ERROR(status)) {
708 hdd_err("Failed to set keepalive");
709 return qdf_status_to_os_return(status);
710 }
711
712 return 0;
713}
714
715/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800716 * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function
717 * @work: registered work item
718 *
719 * This function performs the work initially trigged by a callback
720 * from the IPv4 netdev notifier. Since this means there has been a
721 * change in IPv4 state for the interface, the ARP offload is
722 * reconfigured.
723 *
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;
Dustin Brownb6b0f182017-03-08 13:08:27 -0800731
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530732 ENTER();
Dustin Brownb6b0f182017-03-08 13:08:27 -0800733
Jeff Johnson75b737d2017-08-29 14:24:41 -0700734 adapter = container_of(work, struct hdd_adapter, ipv4NotifierWorkQueue);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700735 errno = hdd_validate_adapter(adapter);
736 if (errno)
737 goto exit;
Dustin Brownb6b0f182017-03-08 13:08:27 -0800738
739 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700740 errno = wlan_hdd_validate_context(hdd_ctx);
741 if (errno)
742 goto exit;
743
744 hdd_enable_arp_offload(adapter, pmo_ipv4_change_notify);
745
Dustin Brownb6b0f182017-03-08 13:08:27 -0800746 if (hdd_ctx->config->sta_keepalive_method == HDD_STA_KEEPALIVE_GRAT_ARP)
747 hdd_set_grat_arp_keepalive(adapter);
748
Dustin Brownf13b8c32017-05-19 17:23:08 -0700749exit:
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530750 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800751}
752
753/**
754 * hdd_ipv4_notifier_work_queue() - IP V4 change notifier work handler
755 * @work: Pointer to work context
756 *
757 * Return: none
758 */
759void hdd_ipv4_notifier_work_queue(struct work_struct *work)
760{
761 cds_ssr_protect(__func__);
762 __hdd_ipv4_notifier_work_queue(work);
763 cds_ssr_unprotect(__func__);
764}
765
766/**
767 * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function
768 * @nb: notifier block that was registered with the kernel
769 * @data: (unused) generic data that was registered with the kernel
770 * @arg: (unused) generic argument that was registered with the kernel
771 *
772 * This is a callback function that is registered with the kernel via
773 * register_inetaddr_notifier() which allows the driver to be
774 * notified when there is an IPv4 address change.
775 *
776 * Return: NOTIFY_DONE to indicate we don't care what happens with
777 * other callbacks
778 */
779static int __wlan_hdd_ipv4_changed(struct notifier_block *nb,
780 unsigned long data, void *arg)
781{
782 struct in_ifaddr *ifa = (struct in_ifaddr *)arg;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800783 struct net_device *ndev = ifa->ifa_dev->dev;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700784 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700785 struct hdd_context *hdd_ctx;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700786 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800787
Jeff Johnson158c8d02016-10-31 13:11:48 -0700788 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530789
Dustin Brownf13b8c32017-05-19 17:23:08 -0700790 errno = hdd_validate_adapter(adapter);
791 if (errno)
792 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793
Dustin Brownf13b8c32017-05-19 17:23:08 -0700794 if (adapter->dev == ndev &&
795 (adapter->device_mode == QDF_STA_MODE ||
796 adapter->device_mode == QDF_P2P_CLIENT_MODE ||
797 adapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800798
Dustin Brownf13b8c32017-05-19 17:23:08 -0700799 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
800 errno = wlan_hdd_validate_context(hdd_ctx);
801 if (errno)
802 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800803
Nachiket Kukadec9045fe2017-06-19 15:14:43 +0530804 /* Ignore if the interface is down */
805 if (!(ndev->flags & IFF_UP)) {
806 hdd_err("Rcvd change addr request on %s(flags 0x%X)",
807 ndev->name, ndev->flags);
808 hdd_err("NETDEV Interface is down, ignoring...");
809 goto exit;
810 }
Padma, Santhosh Kumar8392fb42017-03-17 12:35:27 +0530811 hdd_debug("invoking sme_dhcp_done_ind");
Dustin Brownf13b8c32017-05-19 17:23:08 -0700812 sme_dhcp_done_ind(hdd_ctx->hHal, adapter->sessionId);
Abhishek Singhca408032016-09-13 15:26:12 +0530813
Dustin Brownf13b8c32017-05-19 17:23:08 -0700814 if (!hdd_ctx->config->fhostArpOffload) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800815 hdd_debug("Offload not enabled ARPOffload=%d",
Dustin Brownf13b8c32017-05-19 17:23:08 -0700816 hdd_ctx->config->fhostArpOffload);
817 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800818 }
819
Dustin Brownf13b8c32017-05-19 17:23:08 -0700820 ifa = hdd_lookup_ifaddr(adapter);
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800821 if (ifa && ifa->ifa_local)
Dustin Brownf13b8c32017-05-19 17:23:08 -0700822 schedule_work(&adapter->ipv4NotifierWorkQueue);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800823 }
Dustin Brownf13b8c32017-05-19 17:23:08 -0700824
825exit:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530826 EXIT();
Dustin Brownf13b8c32017-05-19 17:23:08 -0700827
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800828 return NOTIFY_DONE;
829}
830
831/**
832 * wlan_hdd_ipv4_changed() - IPv4 change notifier callback
833 * @nb: pointer to notifier block
834 * @data: data
835 * @arg: arg
836 *
837 * This is the IPv4 notifier callback function gets invoked
838 * if any change in IP and then invoke the function @__wlan_hdd_ipv4_changed
839 * to reconfigure the offload parameters.
840 *
841 * Return: 0 on success, error number otherwise.
842 */
843int wlan_hdd_ipv4_changed(struct notifier_block *nb,
844 unsigned long data, void *arg)
845{
846 int ret;
847
848 cds_ssr_protect(__func__);
849 ret = __wlan_hdd_ipv4_changed(nb, data, arg);
850 cds_ssr_unprotect(__func__);
851
852 return ret;
853}
854
855/**
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530856 * hdd_get_ipv4_local_interface() - get ipv4 local interafce from iface list
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700857 * @adapter: Adapter context for which ARP offload is to be configured
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800858 *
859 * Return:
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530860 * ifa - on successful operation,
861 * NULL - on failure of operation
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800862 */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530863static struct in_ifaddr *hdd_get_ipv4_local_interface(
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700864 struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800865{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530866 struct in_ifaddr **ifap = NULL;
867 struct in_ifaddr *ifa = NULL;
868 struct in_device *in_dev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800869
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700870 in_dev = __in_dev_get_rtnl(adapter->dev);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530871 if (in_dev) {
872 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
873 ifap = &ifa->ifa_next) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700874 if (!strcmp(adapter->dev->name, ifa->ifa_label)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530875 /* if match break */
876 return ifa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800877 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530879 }
880 ifa = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800881
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530882 return ifa;
883}
884
Jeff Johnson75b737d2017-08-29 14:24:41 -0700885void hdd_enable_arp_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530886 enum pmo_offload_trigger trigger)
887{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700888 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530889 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
890 QDF_STATUS status;
891 struct pmo_arp_req *arp_req = NULL;
892 struct in_ifaddr *ifa = NULL;
893
894 ENTER();
895 arp_req = qdf_mem_malloc(sizeof(*arp_req));
896 if (!arp_req) {
897 hdd_err("cannot allocate arp_req");
898 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800899 }
Jeff Johnson68755312017-02-10 11:46:55 -0800900
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530901 arp_req->psoc = psoc;
902 arp_req->vdev_id = adapter->sessionId;
903 arp_req->trigger = trigger;
Jeff Johnson68755312017-02-10 11:46:55 -0800904
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530905 ifa = hdd_get_ipv4_local_interface(adapter);
906 if (ifa && ifa->ifa_local) {
907 arp_req->ipv4_addr = (uint32_t)ifa->ifa_local;
908 status = pmo_ucfg_cache_arp_offload_req(arp_req);
909 if (status == QDF_STATUS_SUCCESS) {
910 status = pmo_ucfg_enable_arp_offload_in_fwr(
911 adapter->hdd_vdev, trigger);
912 if (status == QDF_STATUS_SUCCESS)
913 hdd_wlan_offload_event(
914 PMO_IPV4_ARP_REPLY_OFFLOAD,
915 PMO_OFFLOAD_ENABLE);
916 else
917 hdd_info("fail to enable arp offload in fwr");
918 } else
919 hdd_info("fail to cache arp offload request");
920 } else {
921 hdd_notice("IP Address is not assigned");
922 status = QDF_STATUS_NOT_INITIALIZED;
923 }
924out:
925 if (arp_req)
926 qdf_mem_free(arp_req);
927 EXIT();
928
929}
930
Jeff Johnson75b737d2017-08-29 14:24:41 -0700931void hdd_disable_arp_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530932 enum pmo_offload_trigger trigger)
933{
934 QDF_STATUS status;
935
936 ENTER();
937 status = pmo_ucfg_flush_arp_offload_req(adapter->hdd_vdev);
938 if (status != QDF_STATUS_SUCCESS) {
939 hdd_err("Failed to flush arp Offload");
940 goto out;
Jeff Johnson68755312017-02-10 11:46:55 -0800941 }
942
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530943 status = pmo_ucfg_disable_arp_offload_in_fwr(adapter->hdd_vdev, trigger);
944 if (status == QDF_STATUS_SUCCESS)
945 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD,
946 PMO_OFFLOAD_DISABLE);
947 else
948 hdd_info("fail to disable arp offload");
949out:
950 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800951}
952
Jeff Johnson75b737d2017-08-29 14:24:41 -0700953void hdd_enable_mc_addr_filtering(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530954 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800955{
Jeff Johnson399c6272017-08-30 10:51:00 -0700956 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530957 QDF_STATUS status;
958 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800959
Ravi Joshi24477b72016-07-19 15:45:09 -0700960 ENTER();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530961 if (wlan_hdd_validate_context(hdd_ctx))
962 goto out;
Ravi Joshi24477b72016-07-19 15:45:09 -0700963
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530964 status = pmo_ucfg_enable_mc_addr_filtering_in_fwr(psoc,
965 adapter->sessionId, trigger);
966 if (status != QDF_STATUS_SUCCESS)
967 hdd_info("failed to enable mc list status %d", status);
968out:
Ravi Joshi24477b72016-07-19 15:45:09 -0700969 EXIT();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530970
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800971}
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530972
Jeff Johnson75b737d2017-08-29 14:24:41 -0700973void hdd_disable_mc_addr_filtering(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530974 enum pmo_offload_trigger trigger)
975{
Jeff Johnson399c6272017-08-30 10:51:00 -0700976 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530977 QDF_STATUS status = QDF_STATUS_SUCCESS;
978 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
979
980 ENTER();
981 if (wlan_hdd_validate_context(hdd_ctx))
982 goto out;
983
984 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
985 adapter->sessionId, trigger);
986 if (status != QDF_STATUS_SUCCESS)
987 hdd_info("failed to disable mc list status %d", status);
988out:
989 EXIT();
990
991}
992
993int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config)
994{
995 QDF_STATUS status;
996 int ret = 0;
997
998 ENTER();
999 /* cache mc addr list */
1000 status = pmo_ucfg_cache_mc_addr_list(mc_list_config);
1001 if (status != QDF_STATUS_SUCCESS) {
1002 hdd_info("fail to cache mc list status %d", status);
1003 ret = -EINVAL;
1004 }
1005 EXIT();
1006
1007 return ret;
1008}
1009
Jeff Johnson75b737d2017-08-29 14:24:41 -07001010void hdd_disable_and_flush_mc_addr_list(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301011 enum pmo_offload_trigger trigger)
1012{
Jeff Johnson399c6272017-08-30 10:51:00 -07001013 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301014 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
1015 QDF_STATUS status = QDF_STATUS_SUCCESS;
1016
1017 ENTER();
1018 /* disable mc list first */
1019 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
1020 adapter->sessionId, trigger);
1021 if (status != QDF_STATUS_SUCCESS)
1022 hdd_info("fail to disable mc list");
1023
1024 /* flush mc list */
1025 status = pmo_ucfg_flush_mc_addr_list(psoc, adapter->sessionId);
1026 if (status != QDF_STATUS_SUCCESS)
1027 hdd_info("fail to flush mc list status %d", status);
1028 EXIT();
1029
1030 return;
1031
1032}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001033
1034/**
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001035 * hdd_update_conn_state_mask(): record info needed by wma_suspend_req
1036 * @adapter: adapter to get info from
1037 * @conn_state_mask: mask of connection info
1038 *
1039 * currently only need to send connection info.
1040 */
1041static void
Jeff Johnson75b737d2017-08-29 14:24:41 -07001042hdd_update_conn_state_mask(struct hdd_adapter *adapter, uint32_t *conn_state_mask)
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001043{
1044
1045 eConnectionState connState;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07001046 struct hdd_station_ctx *sta_ctx;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301047
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001048 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301049
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001050 connState = sta_ctx->conn_info.connState;
1051
1052 if (connState == eConnectionState_Associated ||
1053 connState == eConnectionState_IbssConnected)
1054 *conn_state_mask |= (1 << adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001055}
1056
1057/**
1058 * hdd_suspend_wlan() - Driver suspend function
1059 * @callback: Callback function to invoke when driver is ready to suspend
1060 * @callbackContext: Context to pass back to @callback function
1061 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301062 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001063 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301064static int
1065hdd_suspend_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001066{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001067 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001068
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301069 QDF_STATUS status;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001070 struct hdd_adapter *adapter = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001071 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001072 uint32_t conn_state_mask = 0;
Jeff Johnsonc3273322016-07-06 15:28:17 -07001073 hdd_info("WLAN being suspended by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001074
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001075 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1076 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001077 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301078 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001079 }
1080
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301081 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001082 hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001083 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301084 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001085 }
1086
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001087 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301088 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001089 adapter = pAdapterNode->adapter;
1090 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
1091 hdd_err("invalid session id: %d", adapter->sessionId);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301092 goto next_adapter;
1093 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001094
1095 /* stop all TX queues before suspend */
Srinivas Girigowda6598eea2017-07-06 19:26:19 -07001096 hdd_info("Disabling queues");
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001097 wlan_hdd_netif_queue_control(adapter,
Himanshu Agarwal865201d2017-04-12 15:45:31 +05301098 WLAN_STOP_ALL_NETIF_QUEUE,
1099 WLAN_CONTROL_PATH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001100
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001101 /* Configure supported OffLoads */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001102 hdd_enable_host_offloads(adapter, pmo_apps_suspend);
1103 hdd_update_conn_state_mask(adapter, &conn_state_mask);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301104next_adapter:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001105 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, &pNext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001106 pAdapterNode = pNext;
1107 }
1108
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001109 status = pmo_ucfg_psoc_user_space_suspend_req(hdd_ctx->hdd_psoc,
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301110 QDF_SYSTEM_SUSPEND);
1111 if (status != QDF_STATUS_SUCCESS)
1112 return -EAGAIN;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001113
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001114 hdd_ctx->hdd_wlan_suspended = true;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301115 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001116
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301117 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118}
1119
1120/**
1121 * hdd_resume_wlan() - Driver resume function
1122 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301123 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001124 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301125static int hdd_resume_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001126{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001127 struct hdd_context *hdd_ctx;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001128 struct hdd_adapter *adapter = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001129 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301130 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001131
Dustin Brown2d228232016-09-22 15:06:19 -07001132 hdd_info("WLAN being resumed by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001133
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001134 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1135 if (!hdd_ctx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001136 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301137 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001138 }
1139
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301140 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001141 hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001142 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301143 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001144 }
1145
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001146 hdd_ctx->hdd_wlan_suspended = false;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301147 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001148
1149 /*loop through all adapters. Concurrency */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001150 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001151
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301152 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001153 adapter = pAdapterNode->adapter;
1154 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
1155 hdd_err("invalid session id: %d", adapter->sessionId);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301156 goto next_adapter;
1157 }
1158 /* Disable supported OffLoads */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001159 hdd_disable_host_offloads(adapter, pmo_apps_resume);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001160
1161 /* wake the tx queues */
Dustin Brown2d228232016-09-22 15:06:19 -07001162 hdd_info("Enabling queues");
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001163 wlan_hdd_netif_queue_control(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001164 WLAN_WAKE_ALL_NETIF_QUEUE,
1165 WLAN_CONTROL_PATH);
1166
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301167next_adapter:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001168 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, &pNext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001169 pAdapterNode = pNext;
1170 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001171 hdd_ipa_resume(hdd_ctx);
1172 status = pmo_ucfg_psoc_user_space_resume_req(hdd_ctx->hdd_psoc,
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301173 QDF_SYSTEM_SUSPEND);
1174 if (status != QDF_STATUS_SUCCESS)
1175 return -EAGAIN;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001176
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301177 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001178}
1179
1180/**
Komal Seelam78ff65a2016-08-18 15:25:24 +05301181 * hdd_svc_fw_shutdown_ind() - API to send FW SHUTDOWN IND to Userspace
1182 *
1183 * @dev: Device Pointer
1184 *
1185 * Return: None
1186 */
1187void hdd_svc_fw_shutdown_ind(struct device *dev)
1188{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001189 struct hdd_context *hdd_ctx;
Komal Seelam78ff65a2016-08-18 15:25:24 +05301190
1191 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1192
1193 hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
1194 WLAN_SVC_FW_SHUTDOWN_IND,
1195 NULL, 0) : 0;
1196}
1197
1198/**
Arun Khandavallicc544b32017-01-30 19:52:16 +05301199 * hdd_ssr_restart_sap() - restart sap on SSR
1200 * @hdd_ctx: hdd context
1201 *
1202 * Return: nothing
1203 */
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001204static void hdd_ssr_restart_sap(struct hdd_context *hdd_ctx)
Arun Khandavallicc544b32017-01-30 19:52:16 +05301205{
1206 QDF_STATUS status;
1207 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
Jeff Johnson75b737d2017-08-29 14:24:41 -07001208 struct hdd_adapter *adapter;
Arun Khandavallicc544b32017-01-30 19:52:16 +05301209
1210 ENTER();
1211
1212 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
1213 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Jeff Johnson57eb2732017-10-02 11:40:20 -07001214 adapter = adapter_node->adapter;
Arun Khandavallicc544b32017-01-30 19:52:16 +05301215 if (adapter && adapter->device_mode == QDF_SAP_MODE) {
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001216 if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001217 hdd_debug("Restart prev SAP session");
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001218 wlan_hdd_start_sap(adapter, true);
1219 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05301220 }
1221 status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next);
1222 adapter_node = next;
1223 }
1224
1225 EXIT();
1226}
1227
1228/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229 * hdd_wlan_shutdown() - HDD SSR shutdown function
1230 *
1231 * This function is called by the HIF to shutdown the driver during SSR.
1232 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301233 * Return: QDF_STATUS_SUCCESS if the driver was shut down,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001234 * or an error status otherwise
1235 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301236QDF_STATUS hdd_wlan_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001237{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001238 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001239 p_cds_sched_context cds_sched_context = NULL;
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001240 QDF_STATUS qdf_status;
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001241 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001242
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001243 hdd_info("WLAN driver shutting down!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001244
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001245 /* Get the HDD context. */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001246 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1247 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001248 hdd_err("HDD context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301249 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001250 }
1251
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001252 policy_mgr_clear_concurrent_session_count(hdd_ctx->hdd_psoc);
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301253
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001254 hdd_debug("Invoking packetdump deregistration API");
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301255 wlan_deregister_txrx_packetdump();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001256 wlan_cfg80211_cleanup_scan_queue(hdd_ctx->hdd_pdev);
1257 hdd_reset_all_adapters(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001258
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301259 /* Flush cached rx frame queue */
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001260 if (soc)
1261 cdp_flush_cache_rx_queue(soc);
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301262
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301263 /* De-register the HDD callbacks */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001264 hdd_deregister_cb(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265
1266 cds_sched_context = get_cds_sched_ctxt();
1267
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001268 if (hdd_ctx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001269 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001270 hdd_ctx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001271 }
1272#ifdef QCA_CONFIG_SMP
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001273 if (true == hdd_ctx->is_ol_rx_thread_suspended) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001274 complete(&cds_sched_context->ol_resume_rx_event);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001275 hdd_ctx->is_ol_rx_thread_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001276 }
1277#endif
1278
Jeff Johnson7d562272017-09-13 15:12:54 -07001279 qdf_status = cds_sched_close();
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001280 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1281 hdd_err("Failed to close CDS Scheduler");
1282 QDF_ASSERT(false);
1283 }
1284
Manikandan Mohan71844ea2017-07-05 21:51:08 -07001285 hdd_ipa_uc_ssr_deinit();
Nitesh Shah61c10d92016-10-19 19:29:15 +05301286
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001287 hdd_bus_bandwidth_destroy(hdd_ctx);
Prashanth Bhattaab004382016-10-11 16:08:11 -07001288
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001289 hdd_wlan_stop_modules(hdd_ctx, false);
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301290
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001291 hdd_lpass_notify_stop(hdd_ctx);
Yuanyuan Liu3e918e52016-08-17 15:41:35 -07001292
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001293 wlan_objmgr_print_ref_all_objects_per_psoc(hdd_ctx->hdd_psoc);
Yue Ma2be12872017-06-02 13:06:58 -07001294
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001295 hdd_info("WLAN driver shutdown complete");
Yue Ma2be12872017-06-02 13:06:58 -07001296
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301297 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001298}
1299
Sen, Devendra154b3c42017-02-13 20:44:15 +05301300#ifdef FEATURE_WLAN_DIAG_SUPPORT
1301/**
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301302 * hdd_wlan_ssr_reinit_event()- send ssr reinit state
1303 *
1304 * This Function send send ssr reinit state diag event
1305 *
1306 * Return: void.
1307 */
Sen, Devendra154b3c42017-02-13 20:44:15 +05301308static void hdd_wlan_ssr_reinit_event(void)
1309{
1310 WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit);
1311 qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit));
1312 ssr_reinit.status = SSR_SUB_SYSTEM_REINIT;
1313 WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit,
1314 EVENT_WLAN_SSR_REINIT_SUBSYSTEM);
1315}
1316#else
1317static inline void hdd_wlan_ssr_reinit_event(void)
1318{
1319
1320}
1321#endif
1322
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001323/**
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301324 * hdd_send_default_scan_ies - send default scan ies to fw
1325 *
1326 * This function is used to send default scan ies to fw
1327 * in case of wlan re-init
1328 *
1329 * Return: void
1330 */
1331static void hdd_send_default_scan_ies(struct hdd_context *hdd_ctx)
1332{
1333 hdd_adapter_list_node_t *adapter_node, *next;
1334 struct hdd_adapter *adapter;
1335 QDF_STATUS status;
1336
1337 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
1338 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
Jeff Johnson57eb2732017-10-02 11:40:20 -07001339 adapter = adapter_node->adapter;
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301340 if (hdd_is_interface_up(adapter) &&
1341 (adapter->device_mode == QDF_STA_MODE ||
1342 adapter->device_mode == QDF_P2P_DEVICE_MODE)) {
1343 sme_set_default_scan_ie(hdd_ctx->hHal,
1344 adapter->sessionId,
1345 adapter->scan_info.default_scan_ies,
1346 adapter->scan_info.default_scan_ies_len);
1347 }
1348 status = hdd_get_next_adapter(hdd_ctx, adapter_node,
1349 &next);
1350 adapter_node = next;
1351 }
1352}
1353
1354/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001355 * hdd_wlan_re_init() - HDD SSR re-init function
1356 *
1357 * This function is called by the HIF to re-initialize the driver after SSR.
1358 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301359 * Return: QDF_STATUS_SUCCESS if the driver was re-initialized,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001360 * or an error status otherwise
1361 */
Arun Khandavallifae92942016-08-01 13:31:08 +05301362QDF_STATUS hdd_wlan_re_init(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001363{
Arun Khandavallifae92942016-08-01 13:31:08 +05301364
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001365 struct hdd_context *hdd_ctx = NULL;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001366 struct hdd_adapter *adapter;
Arun Khandavallifae92942016-08-01 13:31:08 +05301367 int ret;
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301368 bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001369
1370 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1371
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001372 /* Get the HDD context */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001373 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1374 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001375 hdd_err("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001376 goto err_re_init;
1377 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001378 bug_on_reinit_failure = hdd_ctx->config->bug_on_reinit_failure;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001379
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001380 /* The driver should always be initialized in STA mode after SSR */
1381 hdd_set_conparam(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001382 /* Try to get an adapter from mode ID */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001383 adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE);
1384 if (!adapter) {
1385 adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
1386 if (!adapter) {
1387 adapter = hdd_get_adapter(hdd_ctx, QDF_IBSS_MODE);
1388 if (!adapter) {
1389 adapter = hdd_get_adapter(hdd_ctx,
1390 QDF_MONITOR_MODE);
1391 if (!adapter)
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001392 hdd_err("Failed to get Adapter!");
Arunk Khandavalli062fb032017-10-04 12:18:15 +05301393 }
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301394
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001395 }
1396 }
1397
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001398 if (hdd_ctx->config->enable_dp_trace)
1399 hdd_dp_trace_init(hdd_ctx->config);
Nirav Shahcc1f1ae2016-04-26 11:41:29 +05301400
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001401 hdd_bus_bandwidth_init(hdd_ctx);
Prashanth Bhattaab004382016-10-11 16:08:11 -07001402
Arun Khandavallicc544b32017-01-30 19:52:16 +05301403
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001404 ret = hdd_wlan_start_modules(hdd_ctx, adapter, true);
Arun Khandavallifae92942016-08-01 13:31:08 +05301405 if (ret) {
1406 hdd_err("Failed to start wlan after error");
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301407 goto err_re_init;
Arun Khandavallifae92942016-08-01 13:31:08 +05301408 }
1409
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001410 hdd_wlan_get_version(hdd_ctx, NULL, NULL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001412 wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
Wu Gao36717432016-11-21 15:09:48 +08001413 WLAN_SVC_FW_CRASHED_IND, NULL, 0);
1414
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001415 /* Restart all adapters */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001416 hdd_start_all_adapters(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001417
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001418 hdd_ctx->last_scan_reject_session_id = 0xFF;
1419 hdd_ctx->last_scan_reject_reason = 0;
1420 hdd_ctx->last_scan_reject_timestamp = 0;
1421 hdd_ctx->scan_reject_cnt = 0;
Sreelakshmi Konamkib53c6292017-03-01 13:13:23 +05301422
Selvaraj, Sridhar1c487562017-04-19 14:29:07 +05301423 hdd_set_roaming_in_progress(false);
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001424 complete(&adapter->roaming_comp_var);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001425 hdd_ctx->btCoexModeSet = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001426
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001427 /* Allow the phone to go to sleep */
1428 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05301429 /* set chip power save failure detected callback */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001430 sme_set_chip_pwr_save_fail_cb(hdd_ctx->hHal,
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05301431 hdd_chip_pwr_save_fail_detected_cb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001432
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001433 ret = hdd_register_cb(hdd_ctx);
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301434 if (ret) {
1435 hdd_err("Failed to register HDD callbacks!");
Chandrasekaran Manishekarcde33d72016-04-14 19:03:39 +05301436 goto err_cds_disable;
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301437 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001439 hdd_lpass_notify_start(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001440
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301441 hdd_send_default_scan_ies(hdd_ctx);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001442 hdd_info("WLAN host driver reinitiation completed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001443 goto success;
1444
1445err_cds_disable:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001446 hdd_wlan_stop_modules(hdd_ctx, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001447
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001448err_re_init:
1449 /* Allow the phone to go to sleep */
1450 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301451 if (bug_on_reinit_failure)
1452 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453 return -EPERM;
1454
1455success:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001456 if (hdd_ctx->config->sap_internal_restart)
1457 hdd_ssr_restart_sap(hdd_ctx);
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301458
Sen, Devendra154b3c42017-02-13 20:44:15 +05301459 hdd_wlan_ssr_reinit_event();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301460 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001461}
1462
Jeff Johnson75b737d2017-08-29 14:24:41 -07001463int wlan_hdd_set_powersave(struct hdd_adapter *adapter,
Dustin Brownf660fb42016-09-09 12:04:00 -07001464 bool allow_power_save, uint32_t timeout)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001465{
1466 tHalHandle hal;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001467 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001468
1469 if (NULL == adapter) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001470 hdd_err("Adapter NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001471 return -ENODEV;
1472 }
1473
1474 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1475 if (!hdd_ctx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001476 hdd_err("hdd context is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001477 return -EINVAL;
1478 }
1479
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001480 hdd_debug("Allow power save: %d", allow_power_save);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001481 hal = WLAN_HDD_GET_HAL_CTX(adapter);
1482
Dustin Brown84411b02017-07-21 16:44:44 -07001483 /*
1484 * This is a workaround for defective AP's that send a disassoc
1485 * immediately after WPS connection completes. Defer powersave by a
1486 * small amount if the affected AP is detected.
1487 */
1488 if (allow_power_save &&
1489 adapter->device_mode == QDF_STA_MODE &&
Krunal Soni364e0872017-05-10 21:24:34 -07001490 !adapter->sessionCtx.station.ap_supports_immediate_power_save) {
1491 /* override user's requested flag */
Krunal Soni364e0872017-05-10 21:24:34 -07001492 allow_power_save = false;
Dustin Brown84411b02017-07-21 16:44:44 -07001493 timeout = AUTO_PS_DEFER_TIMEOUT_MS;
1494 hdd_debug("Defer power-save due to AP spec non-conformance");
Krunal Soni364e0872017-05-10 21:24:34 -07001495 }
1496
Dustin Brownf660fb42016-09-09 12:04:00 -07001497 if (allow_power_save) {
1498 if (QDF_STA_MODE == adapter->device_mode ||
1499 QDF_P2P_CLIENT_MODE == adapter->device_mode) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001500 hdd_debug("Disabling Auto Power save timer");
Dustin Brownf660fb42016-09-09 12:04:00 -07001501 sme_ps_disable_auto_ps_timer(
1502 WLAN_HDD_GET_HAL_CTX(adapter),
1503 adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001504 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001505
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001506 if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001507 hdd_debug("Wlan driver Entering Power save");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001508
1509 /*
1510 * Enter Power Save command received from GUI
1511 * this means DHCP is completed
1512 */
1513 sme_ps_enable_disable(hal, adapter->sessionId,
1514 SME_PS_ENABLE);
1515 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001516 hdd_debug("Power Save is not enabled in the cfg");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001517 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001518 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001519 hdd_debug("Wlan driver Entering Full Power");
Dustin Brownf660fb42016-09-09 12:04:00 -07001520
1521 /*
1522 * Enter Full power command received from GUI
1523 * this means we are disconnected
1524 */
1525 sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1526 adapter->sessionId);
1527 sme_ps_enable_disable(hal, adapter->sessionId, SME_PS_DISABLE);
1528 sme_ps_enable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
Dustin Brown84411b02017-07-21 16:44:44 -07001529 adapter->sessionId, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001530 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001531
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001532 return 0;
1533}
1534
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001535static void wlan_hdd_print_suspend_fail_stats(struct hdd_context *hdd_ctx)
Dustin Brown105d7902016-10-03 16:27:59 -07001536{
Dustin Brownd9322482017-01-09 12:46:03 -08001537 struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301538
Dustin Brown105d7902016-10-03 16:27:59 -07001539 hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d",
Dustin Brownd9322482017-01-09 12:46:03 -08001540 stats->suspend_fail[SUSPEND_FAIL_IPA],
1541 stats->suspend_fail[SUSPEND_FAIL_RADAR],
1542 stats->suspend_fail[SUSPEND_FAIL_ROAM],
1543 stats->suspend_fail[SUSPEND_FAIL_SCAN],
1544 stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]);
Dustin Brown105d7902016-10-03 16:27:59 -07001545}
1546
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001547void wlan_hdd_inc_suspend_stats(struct hdd_context *hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001548 enum suspend_fail_reason reason)
1549{
1550 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001551 hdd_ctx->suspend_resume_stats.suspend_fail[reason]++;
Dustin Brown105d7902016-10-03 16:27:59 -07001552 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
1553}
1554
Dustin Brown5fbb1052017-08-11 17:25:51 -07001555#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
1556static inline void
1557hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
1558{
1559 cfg80211_sched_scan_results(wiphy);
1560}
1561#else
1562static inline void
1563hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
1564{
1565 cfg80211_sched_scan_results(wiphy, reqid);
1566}
1567#endif
1568
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001569/**
1570 * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1571 * @wiphy: Pointer to wiphy
1572 *
1573 * This API is called when cfg80211 driver resumes driver updates
1574 * latest sched_scan scan result(if any) to cfg80211 database
1575 *
1576 * Return: integer status
1577 */
1578static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1579{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001580 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001581 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001582 hdd_adapter_list_node_t *pAdapterNode, *pNext;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301583 QDF_STATUS status = QDF_STATUS_SUCCESS;
Dustin Brownd9322482017-01-09 12:46:03 -08001584 int exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001585 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1586
1587 ENTER();
1588
Dustin Brownd9322482017-01-09 12:46:03 -08001589 if (cds_is_driver_recovering()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001590 hdd_debug("Driver is recovering; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001591 exit_code = 0;
1592 goto exit_with_code;
1593 }
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001594
Anurag Chouhan6d760662016-02-20 16:05:43 +05301595 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001596 hdd_err("Command not allowed in FTM mode");
Dustin Brownd9322482017-01-09 12:46:03 -08001597 exit_code = -EINVAL;
1598 goto exit_with_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001599 }
1600
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001601 exit_code = wlan_hdd_validate_context(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001602 if (exit_code) {
1603 hdd_err("Invalid HDD context");
1604 goto exit_with_code;
1605 }
Arun Khandavallifae92942016-08-01 13:31:08 +05301606
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001607 mutex_lock(&hdd_ctx->iface_change_lock);
1608 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1609 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001610 hdd_debug("Driver is not enabled; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001611 exit_code = 0;
1612 goto exit_with_code;
Arun Khandavallifae92942016-08-01 13:31:08 +05301613 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001614 mutex_unlock(&hdd_ctx->iface_change_lock);
Dustin Brownd9322482017-01-09 12:46:03 -08001615
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001616 pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_MEDIUM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001617
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301618 status = hdd_resume_wlan();
1619 if (status != QDF_STATUS_SUCCESS) {
1620 exit_code = 0;
1621 goto exit_with_code;
1622 }
Rajeev Kumareada0d02016-12-08 17:44:17 -08001623 /* Resume control path scheduler */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001624 if (hdd_ctx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001625 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001626 hdd_ctx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001627 }
1628#ifdef QCA_CONFIG_SMP
1629 /* Resume tlshim Rx thread */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001630 if (hdd_ctx->is_ol_rx_thread_suspended) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001631 complete(&cds_sched_context->ol_resume_rx_event);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001632 hdd_ctx->is_ol_rx_thread_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001633 }
1634#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001635
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301636 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301637 TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001638 NO_SESSION, hdd_ctx->isWiphySuspended));
1639 qdf_spin_lock(&hdd_ctx->sched_scan_lock);
1640 hdd_ctx->isWiphySuspended = false;
1641 if (true != hdd_ctx->isSchedScanUpdatePending) {
1642 qdf_spin_unlock(&hdd_ctx->sched_scan_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001643 hdd_debug("Return resume is not due to PNO indication");
Dustin Brownd9322482017-01-09 12:46:03 -08001644 goto exit_with_success;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645 }
1646 /* Reset flag to avoid updatating cfg80211 data old results again */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001647 hdd_ctx->isSchedScanUpdatePending = false;
1648 qdf_spin_unlock(&hdd_ctx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001649
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001650 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301651 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001652 adapter = pAdapterNode->adapter;
1653 if ((NULL != adapter) &&
1654 (QDF_STA_MODE == adapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001655 if (0 !=
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001656 wlan_hdd_cfg80211_update_bss(hdd_ctx->wiphy,
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001657 adapter, 0)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001658 hdd_warn("NO SCAN result");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001659 } else {
1660 /* Acquire wakelock to handle the case where
1661 * APP's tries to suspend immediately after
1662 * updating the scan results. Whis results in
1663 * app's is in suspended state and not able to
1664 * process the connect request to AP
1665 */
Sreelakshmi Konamki22528532016-09-06 16:34:50 +05301666 hdd_prevent_suspend_timeout(
Dustin Brownceed67e2017-05-26 11:57:31 -07001667 HDD_WAKELOCK_TIMEOUT_RESUME,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668 WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001669 hdd_sched_scan_results(hdd_ctx->wiphy, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670 }
1671
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001672 hdd_debug("cfg80211 scan result database updated");
Dustin Brownd9322482017-01-09 12:46:03 -08001673 goto exit_with_success;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001674 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001675 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, &pNext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001676 pAdapterNode = pNext;
1677 }
1678
Dustin Brownd9322482017-01-09 12:46:03 -08001679exit_with_success:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001680 hdd_ctx->suspend_resume_stats.resumes++;
Dustin Brownd9322482017-01-09 12:46:03 -08001681 exit_code = 0;
1682
1683exit_with_code:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301684 EXIT();
Dustin Brownd9322482017-01-09 12:46:03 -08001685 return exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001686}
1687
1688/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689 * wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1690 * @wiphy: Pointer to wiphy
1691 *
1692 * This API is called when cfg80211 driver resumes driver updates
1693 * latest sched_scan scan result(if any) to cfg80211 database
1694 *
1695 * Return: integer status
1696 */
1697int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1698{
1699 int ret;
1700
1701 cds_ssr_protect(__func__);
1702 ret = __wlan_hdd_cfg80211_resume_wlan(wiphy);
1703 cds_ssr_unprotect(__func__);
1704
1705 return ret;
1706}
1707
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001708static void hdd_suspend_cb(void)
1709{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001710 struct hdd_context *hdd_ctx;
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001711
1712 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1713 if (!hdd_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001714 hdd_err("HDD context is NULL");
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001715 return;
1716 }
1717
1718 complete(&hdd_ctx->mc_sus_event_var);
1719}
1720
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721/**
1722 * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1723 * @wiphy: Pointer to wiphy
1724 * @wow: Pointer to wow
1725 *
1726 * This API is called when cfg80211 driver suspends
1727 *
1728 * Return: integer status
1729 */
1730static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1731 struct cfg80211_wowlan *wow)
1732{
1733#ifdef QCA_CONFIG_SMP
1734#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */
1735#endif
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001736 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001737 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1738 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001739 struct hdd_adapter *adapter;
Jeff Johnson37588942017-08-15 16:11:41 -07001740 struct hdd_scan_info *pScanInfo;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301741 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742 int rc;
1743
1744 ENTER();
1745
Anurag Chouhan6d760662016-02-20 16:05:43 +05301746 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001747 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001748 return -EINVAL;
1749 }
1750
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001751 rc = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301752 if (0 != rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001754
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001755 mutex_lock(&hdd_ctx->iface_change_lock);
1756 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1757 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001758 hdd_debug("Driver Modules not Enabled ");
Arun Khandavallifae92942016-08-01 13:31:08 +05301759 return 0;
1760 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001761 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavallifae92942016-08-01 13:31:08 +05301762
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763 /* If RADAR detection is in progress (HDD), prevent suspend. The flag
1764 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true
1765 * until CAC is done for a SoftAP which is in started state.
1766 */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001767 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301768 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001769 adapter = pAdapterNode->adapter;
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301770
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001771 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
1772 hdd_err("invalid session id: %d", adapter->sessionId);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301773 goto next_adapter;
1774 }
1775
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001776 if (QDF_SAP_MODE == adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001777 if (BSS_START ==
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001778 WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter)->bssState &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001779 true ==
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001780 WLAN_HDD_GET_AP_CTX_PTR(adapter)->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001781 dfs_cac_block_tx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001782 hdd_err("RADAR detection in progress, do not allow suspend");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001783 wlan_hdd_inc_suspend_stats(hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001784 SUSPEND_FAIL_RADAR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001785 return -EAGAIN;
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001786 } else if (!hdd_ctx->config->enableSapSuspend) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001787 /* return -EOPNOTSUPP if SAP does not support
1788 * suspend
1789 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001790 hdd_err("SAP does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001791 return -EOPNOTSUPP;
1792 }
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001793 } else if (QDF_P2P_GO_MODE == adapter->device_mode) {
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001794 if (!hdd_ctx->config->enableSapSuspend) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001795 /* return -EOPNOTSUPP if GO does not support
1796 * suspend
1797 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001798 hdd_err("GO does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001799 return -EOPNOTSUPP;
1800 }
1801 }
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001802 if (adapter->is_roc_inprogress)
1803 wlan_hdd_cleanup_remain_on_channel_ctx(adapter);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301804next_adapter:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001805 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, &pNext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001806 pAdapterNode = pNext;
1807 }
1808
1809 /* Stop ongoing scan on each interface */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001810 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301811 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001812 adapter = pAdapterNode->adapter;
1813 pScanInfo = &adapter->scan_info;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001814
Sandeep Puligillaf8527122016-11-16 18:35:16 -08001815 if (sme_neighbor_middle_of_roaming
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001816 (hdd_ctx->hHal, adapter->sessionId)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001817 hdd_err("Roaming in progress, do not allow suspend");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001818 wlan_hdd_inc_suspend_stats(hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001819 SUSPEND_FAIL_ROAM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001820 return -EAGAIN;
1821 }
1822
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001823 wlan_abort_scan(hdd_ctx->hdd_pdev, INVAL_PDEV_ID,
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001824 adapter->sessionId, INVALID_SCAN_ID, false);
Dustin Brownc86d5362017-07-07 13:08:51 -07001825
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001826 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, &pNext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001827 pAdapterNode = pNext;
1828 }
1829
Dustin Brown84411b02017-07-21 16:44:44 -07001830 /* flush any pending powersave timers */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001831 status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode);
Dustin Brown84411b02017-07-21 16:44:44 -07001832 while (pAdapterNode && QDF_IS_STATUS_SUCCESS(status)) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001833 adapter = pAdapterNode->adapter;
Dustin Brown84411b02017-07-21 16:44:44 -07001834
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001835 sme_ps_timer_flush_sync(hdd_ctx->hHal, adapter->sessionId);
Dustin Brown84411b02017-07-21 16:44:44 -07001836
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001837 status = hdd_get_next_adapter(hdd_ctx, pAdapterNode,
Dustin Brown84411b02017-07-21 16:44:44 -07001838 &pAdapterNode);
1839 }
1840
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001841 /*
1842 * Suspend IPA early before proceeding to suspend other entities like
1843 * firmware to avoid any race conditions.
1844 */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001845 if (hdd_ipa_suspend(hdd_ctx)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001846 hdd_err("IPA not ready to suspend!");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001847 wlan_hdd_inc_suspend_stats(hdd_ctx, SUSPEND_FAIL_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001848 return -EAGAIN;
1849 }
1850
Rajeev Kumareada0d02016-12-08 17:44:17 -08001851 /* Suspend control path scheduler */
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001852 scheduler_register_hdd_suspend_callback(hdd_suspend_cb);
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301853 scheduler_set_event_mask(MC_SUSPEND_EVENT);
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001854 scheduler_wake_up_controller_thread();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001855
Rajeev Kumareada0d02016-12-08 17:44:17 -08001856 /* Wait for suspend confirmation from scheduler */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001857 rc = wait_for_completion_timeout(&hdd_ctx->mc_sus_event_var,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858 msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
1859 if (!rc) {
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301860 scheduler_clear_event_mask(MC_SUSPEND_EVENT);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001861 hdd_err("Failed to stop mc thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862 goto resume_tx;
1863 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001864 hdd_ctx->is_scheduler_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001865
1866#ifdef QCA_CONFIG_SMP
1867 /* Suspend tlshim rx thread */
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301868 set_bit(RX_SUSPEND_EVENT, &cds_sched_context->ol_rx_event_flag);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001869 wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue);
1870 rc = wait_for_completion_timeout(&cds_sched_context->
1871 ol_suspend_rx_event,
1872 msecs_to_jiffies
1873 (RX_TLSHIM_SUSPEND_TIMEOUT));
1874 if (!rc) {
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301875 clear_bit(RX_SUSPEND_EVENT,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001876 &cds_sched_context->ol_rx_event_flag);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001877 hdd_err("Failed to stop tl_shim rx thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878 goto resume_all;
1879 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001880 hdd_ctx->is_ol_rx_thread_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881#endif
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301882 if (hdd_suspend_wlan() < 0)
1883 goto resume_all;
1884
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301885 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301886 TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001887 NO_SESSION, hdd_ctx->isWiphySuspended));
1888 hdd_ctx->isWiphySuspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001889
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001890 pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_NONE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891
1892 EXIT();
1893 return 0;
1894
1895#ifdef QCA_CONFIG_SMP
1896resume_all:
1897
Rajeev Kumar0b732952016-12-08 17:51:39 -08001898 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001899 hdd_ctx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900#endif
1901
1902resume_tx:
1903
1904 hdd_resume_wlan();
1905 return -ETIME;
1906
1907}
1908
1909/**
1910 * wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1911 * @wiphy: Pointer to wiphy
1912 * @wow: Pointer to wow
1913 *
1914 * This API is called when cfg80211 driver suspends
1915 *
1916 * Return: integer status
1917 */
1918int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1919 struct cfg80211_wowlan *wow)
1920{
1921 int ret;
1922
1923 cds_ssr_protect(__func__);
1924 ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
1925 cds_ssr_unprotect(__func__);
1926
1927 return ret;
1928}
1929
1930/**
Komal Seelama89be8d2016-09-29 11:09:26 +05301931 * hdd_stop_dhcp_ind() - API to stop DHCP sequence
1932 * @adapter: Adapter on which DHCP needs to be stopped
1933 *
1934 * Release the wakelock held for DHCP process and allow
1935 * the runtime pm to continue
1936 *
1937 * Return: None
1938 */
Jeff Johnson75b737d2017-08-29 14:24:41 -07001939static void hdd_stop_dhcp_ind(struct hdd_adapter *adapter)
Komal Seelama89be8d2016-09-29 11:09:26 +05301940{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001941 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Komal Seelama89be8d2016-09-29 11:09:26 +05301942
Srinivas Girigowdac06543c2017-03-09 15:10:03 -08001943 hdd_debug("DHCP stop indicated through power save");
Komal Seelama89be8d2016-09-29 11:09:26 +05301944 sme_dhcp_stop_ind(hdd_ctx->hHal, adapter->device_mode,
1945 adapter->macAddressCurrent.bytes,
1946 adapter->sessionId);
1947 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -08001948 qdf_runtime_pm_allow_suspend(&adapter->connect_rpm_ctx.connect);
Komal Seelama89be8d2016-09-29 11:09:26 +05301949}
1950
1951/**
1952 * hdd_start_dhcp_ind() - API to start DHCP sequence
1953 * @adapter: Adapter on which DHCP needs to be stopped
1954 *
1955 * Prevent APPS suspend and the runtime suspend during
1956 * DHCP sequence
1957 *
1958 * Return: None
1959 */
Jeff Johnson75b737d2017-08-29 14:24:41 -07001960static void hdd_start_dhcp_ind(struct hdd_adapter *adapter)
Komal Seelama89be8d2016-09-29 11:09:26 +05301961{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001962 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Komal Seelama89be8d2016-09-29 11:09:26 +05301963
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001964 hdd_debug("DHCP start indicated through power save");
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -08001965 qdf_runtime_pm_prevent_suspend(&adapter->connect_rpm_ctx.connect);
Dustin Brownceed67e2017-05-26 11:57:31 -07001966 hdd_prevent_suspend_timeout(HDD_WAKELOCK_TIMEOUT_CONNECT,
1967 WIFI_POWER_EVENT_WAKELOCK_DHCP);
Komal Seelama89be8d2016-09-29 11:09:26 +05301968 sme_dhcp_start_ind(hdd_ctx->hHal, adapter->device_mode,
1969 adapter->macAddressCurrent.bytes,
1970 adapter->sessionId);
1971}
1972
1973/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001974 * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
1975 * @wiphy: Pointer to wiphy
1976 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07001977 * @allow_power_save: is wlan allowed to go into power save mode
1978 * @timeout: Timeout value in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001979 *
1980 * Return: 0 for success, non-zero for failure
1981 */
1982static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07001983 struct net_device *dev,
1984 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001985 int timeout)
1986{
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001987 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001988 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001989 int status;
1990
Dustin Brownecfce632016-09-13 10:41:45 -07001991 ENTER();
1992
Dustin Brownf660fb42016-09-09 12:04:00 -07001993 if (timeout < 0) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001994 hdd_debug("User space timeout: %d; Using default instead: %d",
Dustin Brownf660fb42016-09-09 12:04:00 -07001995 timeout, AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE);
1996 timeout = AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE;
1997 }
1998
Anurag Chouhan6d760662016-02-20 16:05:43 +05301999 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002000 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002001 return -EINVAL;
2002 }
2003
Jeff Johnsonf6d24282017-10-02 13:25:25 -07002004 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2005 hdd_err("invalid session id: %d", adapter->sessionId);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302006 return -EINVAL;
2007 }
2008
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302009 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002010 TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
Jeff Johnsonf6d24282017-10-02 13:25:25 -07002011 adapter->sessionId, timeout));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002012
Jeff Johnsonf6d24282017-10-02 13:25:25 -07002013 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002014 status = wlan_hdd_validate_context(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302016 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002017 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002018
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002019 mutex_lock(&hdd_ctx->iface_change_lock);
2020 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2021 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002022 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05302023 return 0;
2024 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002025 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavalli99286452016-08-22 12:13:41 +05302026
Jeff Johnsonf6d24282017-10-02 13:25:25 -07002027 status = wlan_hdd_set_powersave(adapter, allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002028
Jeff Johnsonf6d24282017-10-02 13:25:25 -07002029 allow_power_save ? hdd_stop_dhcp_ind(adapter) :
2030 hdd_start_dhcp_ind(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031
2032 EXIT();
2033 return status;
2034}
2035
2036/**
2037 * wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
2038 * @wiphy: Pointer to wiphy
2039 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07002040 * @allow_power_save: is wlan allowed to go into power save mode
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002041 * @timeout: Timeout value
2042 *
2043 * Return: 0 for success, non-zero for failure
2044 */
2045int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07002046 struct net_device *dev,
2047 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048 int timeout)
2049{
2050 int ret;
2051
2052 cds_ssr_protect(__func__);
Dustin Brownf660fb42016-09-09 12:04:00 -07002053 ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev,
2054 allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 cds_ssr_unprotect(__func__);
2056
2057 return ret;
2058}
2059
2060/**
2061 * __wlan_hdd_cfg80211_set_txpower() - set TX power
2062 * @wiphy: Pointer to wiphy
2063 * @wdev: Pointer to network device
2064 * @type: TX power setting type
2065 * @dbm: TX power in dbm
2066 *
2067 * Return: 0 for success, non-zero for failure
2068 */
2069static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002070 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002071 enum nl80211_tx_power_setting type,
2072 int dbm)
2073{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002074 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002075 tHalHandle hHal = NULL;
Anurag Chouhan6d760662016-02-20 16:05:43 +05302076 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
2077 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002078 int status;
2079
2080 ENTER();
2081
Anurag Chouhan6d760662016-02-20 16:05:43 +05302082 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002083 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084 return -EINVAL;
2085 }
2086
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302087 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002088 TRACE_CODE_HDD_CFG80211_SET_TXPOWER,
2089 NO_SESSION, type));
2090
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002091 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302092 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002093 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002094
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002095 hHal = hdd_ctx->hHal;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002096
2097 if (0 != sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, dbm)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002098 hdd_err("sme_cfg_set_int failed for tx power %hu",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002099 dbm);
2100 return -EIO;
2101 }
2102
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002103 hdd_debug("Set tx power level %d dbm", dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002104
2105 switch (type) {
2106 /* Automatically determine transmit power */
2107 case NL80211_TX_POWER_AUTOMATIC:
2108 /* Fall through */
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05302109 case NL80211_TX_POWER_LIMITED:
2110 /* Limit TX power by the mBm parameter */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002111 if (sme_set_max_tx_power(hHal, bssid, selfMac, dbm) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302112 QDF_STATUS_SUCCESS) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002113 hdd_err("Setting maximum tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002114 return -EIO;
2115 }
2116 break;
2117
2118 case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */
Jeff Johnsonc3273322016-07-06 15:28:17 -07002119 hdd_err("NL80211_TX_POWER_FIXED not supported");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002120 return -EOPNOTSUPP;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002121
2122 default:
Jeff Johnsonc3273322016-07-06 15:28:17 -07002123 hdd_err("Invalid power setting type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002124 return -EIO;
2125 }
2126
2127 EXIT();
2128 return 0;
2129}
2130
2131/**
2132 * wlan_hdd_cfg80211_set_txpower() - set TX power
2133 * @wiphy: Pointer to wiphy
2134 * @wdev: Pointer to network device
2135 * @type: TX power setting type
2136 * @dbm: TX power in dbm
2137 *
2138 * Return: 0 for success, non-zero for failure
2139 */
2140int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002141 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002142 enum nl80211_tx_power_setting type,
2143 int dbm)
2144{
2145 int ret;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05302146
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002147 cds_ssr_protect(__func__);
2148 ret = __wlan_hdd_cfg80211_set_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002149 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002150 type, dbm);
2151 cds_ssr_unprotect(__func__);
2152
2153 return ret;
2154}
2155
2156/**
2157 * __wlan_hdd_cfg80211_get_txpower() - get TX power
2158 * @wiphy: Pointer to wiphy
2159 * @wdev: Pointer to network device
2160 * @dbm: Pointer to TX power in dbm
2161 *
2162 * Return: 0 for success, non-zero for failure
2163 */
2164static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002165 struct wireless_dev *wdev,
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002166 int *dbm)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002167{
2168
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002169 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002170 struct net_device *ndev = wdev->netdev;
Jeff Johnson75b737d2017-08-29 14:24:41 -07002171 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002172 int status;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07002173 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002174
2175 ENTER();
2176
Anurag Chouhan6d760662016-02-20 16:05:43 +05302177 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002178 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002179 return -EINVAL;
2180 }
2181
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002182 status = wlan_hdd_validate_context(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002183 if (0 != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002184 *dbm = 0;
2185 return status;
2186 }
2187
Arun Khandavalli99286452016-08-22 12:13:41 +05302188 /* Validate adapter sessionId */
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302189 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2190 hdd_err("invalid session id: %d", adapter->sessionId);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002191 return -EINVAL;
Arun Khandavalli99286452016-08-22 12:13:41 +05302192 }
2193
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002194 mutex_lock(&hdd_ctx->iface_change_lock);
2195 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2196 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002197 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05302198 /* Send cached data to upperlayer*/
2199 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
2200 return 0;
2201 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002202 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavalli99286452016-08-22 12:13:41 +05302203
Ganesh Kondabattinif847f062017-05-26 12:36:24 +05302204 if (sta_ctx->conn_info.connState != eConnectionState_Associated) {
2205 hdd_debug("Not associated");
2206 /*To keep GUI happy */
2207 *dbm = 0;
2208 return 0;
2209 }
2210
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302211 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302212 TRACE_CODE_HDD_CFG80211_GET_TXPOWER,
Arun Khandavalli99286452016-08-22 12:13:41 +05302213 adapter->sessionId, adapter->device_mode));
2214 wlan_hdd_get_class_astats(adapter);
2215 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002216
2217 EXIT();
2218 return 0;
2219}
2220
2221/**
2222 * wlan_hdd_cfg80211_get_txpower() - cfg80211 get power handler function
2223 * @wiphy: Pointer to wiphy structure.
2224 * @wdev: Pointer to wireless_dev structure.
2225 * @dbm: dbm
2226 *
2227 * This is the cfg80211 get txpower handler function which invokes
2228 * the internal function @__wlan_hdd_cfg80211_get_txpower with
2229 * SSR protection.
2230 *
2231 * Return: 0 for success, error number on failure.
2232 */
2233int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002234 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002235 int *dbm)
2236{
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002237 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002238
2239 cds_ssr_protect(__func__);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002240 ret = __wlan_hdd_cfg80211_get_txpower(wiphy, wdev, dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002241 cds_ssr_unprotect(__func__);
2242
2243 return ret;
2244}
Kapil Gupta6213c012016-09-02 19:39:09 +05302245
2246/**
2247 * hdd_set_qpower_config() - set qpower config to firmware
2248 * @adapter: HDD adapter
2249 * @qpower: new qpower config value
2250 *
2251 * Return: 0 on success; Errno on failure
2252 */
Jeff Johnson75b737d2017-08-29 14:24:41 -07002253int hdd_set_qpower_config(struct hdd_context *hddctx, struct hdd_adapter *adapter,
Dustin Brown10a7b712016-10-07 10:31:16 -07002254 u8 qpower)
Kapil Gupta6213c012016-09-02 19:39:09 +05302255{
Dustin Brown10a7b712016-10-07 10:31:16 -07002256 QDF_STATUS status;
Kapil Gupta6213c012016-09-02 19:39:09 +05302257
2258 if (!hddctx->config->enablePowersaveOffload) {
2259 hdd_err("qpower is disabled in configuration");
2260 return -EINVAL;
2261 }
Manjeet Singh91b7bb82017-02-10 18:35:40 +05302262 if (adapter->device_mode != QDF_STA_MODE &&
2263 adapter->device_mode != QDF_P2P_CLIENT_MODE) {
2264 hdd_info(FL("QPOWER only allowed in STA/P2P-Client modes:%d "),
2265 adapter->device_mode);
2266 return -EINVAL;
2267 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002268
Kapil Gupta6213c012016-09-02 19:39:09 +05302269 if (qpower > PS_DUTY_CYCLING_QPOWER ||
2270 qpower < PS_LEGACY_NODEEPSLEEP) {
Dustin Brown10a7b712016-10-07 10:31:16 -07002271 hdd_err("invalid qpower value: %d", qpower);
Kapil Gupta6213c012016-09-02 19:39:09 +05302272 return -EINVAL;
2273 }
Kapil Gupta6213c012016-09-02 19:39:09 +05302274
Kiran Kumar Lokere7006e0a2017-03-07 19:28:36 -08002275 if (hddctx->config->nMaxPsPoll) {
2276 if ((qpower == PS_QPOWER_NODEEPSLEEP) ||
2277 (qpower == PS_LEGACY_NODEEPSLEEP))
2278 qpower = PS_LEGACY_NODEEPSLEEP;
2279 else
2280 qpower = PS_LEGACY_DEEPSLEEP;
2281 hdd_info("Qpower disabled, %d", qpower);
2282 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002283 status = wma_set_qpower_config(adapter->sessionId, qpower);
2284 if (status != QDF_STATUS_SUCCESS) {
2285 hdd_err("failed to configure qpower: %d", status);
2286 return -EINVAL;
Kapil Gupta6213c012016-09-02 19:39:09 +05302287 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002288
Kapil Gupta6213c012016-09-02 19:39:09 +05302289 return 0;
2290}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002291
Dustin Brown54096432017-02-23 13:00:44 -08002292
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002293#ifdef WLAN_SUSPEND_RESUME_TEST
Dustin Brownbc81a472016-10-26 16:56:59 -07002294static struct net_device *g_dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002295static struct wiphy *g_wiphy;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002296static enum wow_resume_trigger g_resume_trigger;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002297
2298#define HDD_FA_SUSPENDED_BIT (0)
2299static unsigned long fake_apps_state;
2300
Dustin Brownd53d1a82016-10-03 12:57:33 -07002301/**
2302 * __hdd_wlan_fake_apps_resume() - The core logic for
2303 * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(),
2304 * which is only need for non-irq resume
Dustin Brownbc81a472016-10-26 16:56:59 -07002305 * @wiphy: the kernel wiphy struct for the device being resumed
2306 * @dev: the kernel net_device struct for the device being resumed
Dustin Brownd53d1a82016-10-03 12:57:33 -07002307 *
Dustin Brownbc81a472016-10-26 16:56:59 -07002308 * Return: none, calls QDF_BUG() on failure
Dustin Brownd53d1a82016-10-03 12:57:33 -07002309 */
Dustin Brownbc81a472016-10-26 16:56:59 -07002310static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy,
2311 struct net_device *dev)
Dustin Brownd53d1a82016-10-03 12:57:33 -07002312{
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002313 struct hif_opaque_softc *hif_ctx;
Dustin Brownddb59702017-01-12 16:20:31 -08002314 qdf_device_t qdf_dev;
Dustin Brownd53d1a82016-10-03 12:57:33 -07002315
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002316 hdd_info("Unit-test resume WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002317
2318 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2319 if (!qdf_dev) {
2320 hdd_err("Failed to get QDF device context");
2321 QDF_BUG(0);
2322 return;
2323 }
2324
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002325 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2326 if (!hif_ctx) {
2327 hdd_err("Failed to get HIF context");
2328 return;
2329 }
2330
Dustin Brownd53d1a82016-10-03 12:57:33 -07002331 if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002332 hdd_alert("Not unit-test suspended; Nothing to do");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002333 return;
2334 }
2335
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002336 /* simulate kernel disable irqs */
2337 QDF_BUG(!hif_apps_wake_irq_disable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002338
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002339 QDF_BUG(!wlan_hdd_bus_resume_noirq());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002340
2341 /* simulate kernel enable irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002342 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002343
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002344 QDF_BUG(!wlan_hdd_bus_resume());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002345
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002346 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
2347
2348 if (g_resume_trigger == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2349 hif_vote_link_down(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002350
2351 dev->watchdog_timeo = HDD_TX_TIMEOUT;
Dustin Brown562b9672016-12-22 15:25:33 -08002352
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002353 hdd_alert("Unit-test resume succeeded");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002354}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002355
2356/**
2357 * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming
2358 * from unit-test initiated suspend from irq wakeup signal
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002359 *
2360 * Resume wlan after getting very 1st CE interrupt from target
2361 *
2362 * Return: none
2363 */
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002364static void hdd_wlan_fake_apps_resume_irq_callback(void)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002365{
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002366 hdd_info("Trigger unit-test resume WLAN");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002367
2368 QDF_BUG(g_wiphy);
Dustin Brownbc81a472016-10-26 16:56:59 -07002369 QDF_BUG(g_dev);
2370 __hdd_wlan_fake_apps_resume(g_wiphy, g_dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002371 g_wiphy = NULL;
Dustin Brownbc81a472016-10-26 16:56:59 -07002372 g_dev = NULL;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002373}
2374
Dustin Brown54096432017-02-23 13:00:44 -08002375int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev,
2376 enum wow_interface_pause pause_setting,
2377 enum wow_resume_trigger resume_setting)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002378{
Dustin Brownddb59702017-01-12 16:20:31 -08002379 qdf_device_t qdf_dev;
2380 struct hif_opaque_softc *hif_ctx;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002381 int errno;
Dustin Brown54096432017-02-23 13:00:44 -08002382 struct wow_enable_params wow_params = {
2383 .is_unit_test = true,
2384 .interface_pause = pause_setting,
2385 .resume_trigger = resume_setting
2386 };
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002387
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002388 hdd_info("Unit-test suspend WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002389
Dustin Brown54096432017-02-23 13:00:44 -08002390 if (pause_setting < WOW_INTERFACE_PAUSE_DEFAULT ||
2391 pause_setting >= WOW_INTERFACE_PAUSE_COUNT) {
2392 hdd_err("Invalid interface pause %d (expected range [0, 2])",
2393 pause_setting);
2394 return -EINVAL;
2395 }
2396
2397 if (resume_setting < WOW_RESUME_TRIGGER_DEFAULT ||
2398 resume_setting >= WOW_RESUME_TRIGGER_COUNT) {
2399 hdd_err("Invalid resume trigger %d (expected range [0, 2])",
2400 resume_setting);
2401 return -EINVAL;
2402 }
2403
Dustin Brownddb59702017-01-12 16:20:31 -08002404 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2405 if (!qdf_dev) {
2406 hdd_err("Failed to get QDF device context");
2407 return -EINVAL;
2408 }
2409
2410 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2411 if (!hif_ctx) {
2412 hdd_err("Failed to get HIF context");
2413 return -EINVAL;
2414 }
2415
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002416 if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002417 hdd_alert("Already unit-test suspended; Nothing to do");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002418 return 0;
2419 }
2420
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002421 /* pci link is needed to wakeup from HTC wakeup trigger */
2422 if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2423 hif_vote_link_up(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002424
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002425 errno = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL);
2426 if (errno)
2427 goto link_down;
2428
2429 errno = wlan_hdd_unit_test_bus_suspend(wow_params);
2430 if (errno)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002431 goto cfg80211_resume;
2432
2433 /* simulate kernel disabling irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002434 errno = hif_apps_irqs_disable(hif_ctx);
2435 if (errno)
2436 goto bus_resume;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002437
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002438 errno = wlan_hdd_bus_suspend_noirq();
2439 if (errno)
2440 goto enable_irqs;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002441
Dustin Brownbc81a472016-10-26 16:56:59 -07002442 /* pass wiphy/dev to callback via global variables */
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002443 g_wiphy = wiphy;
Dustin Brownbc81a472016-10-26 16:56:59 -07002444 g_dev = dev;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002445 g_resume_trigger = resume_setting;
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002446 hif_ut_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002447
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002448 /* re-enable wake irq */
2449 errno = hif_apps_wake_irq_enable(hif_ctx);
2450 if (errno)
2451 goto fake_apps_resume;
2452
Dustin Brownbc81a472016-10-26 16:56:59 -07002453 /*
2454 * Tell the kernel not to worry if TX queues aren't moving. This is
2455 * expected since we are suspending the wifi hardware, but not APPS
2456 */
2457 dev->watchdog_timeo = INT_MAX;
2458
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002459 hdd_alert("Unit-test suspend succeeded");
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002460
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002461 return 0;
2462
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002463fake_apps_resume:
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002464 hif_ut_apps_resume(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002465
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002466enable_irqs:
2467 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
2468
2469bus_resume:
2470 QDF_BUG(!wlan_hdd_bus_resume());
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002471
2472cfg80211_resume:
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002473 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002474
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002475link_down:
2476 hif_vote_link_down(hif_ctx);
2477
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002478 clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state);
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002479 hdd_err("Unit-test suspend failed: %d", errno);
2480
2481 return errno;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002482}
2483
Dustin Brownbc81a472016-10-26 16:56:59 -07002484int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002485{
Dustin Brownddb59702017-01-12 16:20:31 -08002486 struct hif_opaque_softc *hif_ctx;
2487
2488 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2489 if (!hif_ctx) {
2490 hdd_err("Failed to get HIF context");
2491 return -EINVAL;
2492 }
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002493
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002494 hif_ut_apps_resume(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002495 __hdd_wlan_fake_apps_resume(wiphy, dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002496
2497 return 0;
2498}
2499#endif