blob: dbc74aee59f0729dfcee8ca2fb0737a8be2e92a9 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Jingxiang Geb49aa302018-01-17 20:54:15 +08002 * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080019/**
20 * DOC: wlan_hdd_power.c
21 *
22 * WLAN power management functions
23 *
24 */
25
26/* Include files */
27
28#include <linux/pm.h>
29#include <linux/wait.h>
30#include <linux/cpu.h>
31#include <wlan_hdd_includes.h>
32#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK)
33#include <linux/wakelock.h>
34#endif
Anurag Chouhan6d760662016-02-20 16:05:43 +053035#include "qdf_types.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080036#include "sme_api.h"
37#include <cds_api.h>
38#include <cds_sched.h>
39#include <mac_init_api.h>
40#include <wlan_qct_sys.h>
41#include <wlan_hdd_main.h>
42#include <wlan_hdd_assoc.h>
43#include <wlan_nlink_srv.h>
44#include <wlan_hdd_misc.h>
45#include <wlan_hdd_power.h>
Jeff Johnsonc8d0c252016-10-05 16:19:50 -070046#include <wlan_hdd_host_offload.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080047#include <dbglog_host.h>
48#include <wlan_hdd_trace.h>
Masti, Narayanraddi3e26de62016-08-19 14:33:22 +053049#include <wlan_hdd_p2p.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080050
51#include <linux/semaphore.h>
52#include <wlan_hdd_hostapd.h>
53#include "cfg_api.h"
54
55#include <linux/inetdevice.h>
56#include <wlan_hdd_cfg.h>
Sandeep Puligillae390be52016-02-08 17:07:05 -080057#include <wlan_hdd_scan.h>
Jeff Johnson5fe539b2018-03-23 13:53:30 -070058#include <wlan_hdd_stats.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059#include <wlan_hdd_cfg80211.h>
60#include <net/addrconf.h>
Jeff Johnson2b0a7b82016-05-18 15:08:02 -070061#include <wlan_hdd_lpass.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080062
63#include <wma_types.h>
Poddar, Siddartha78cac32016-12-29 20:08:34 +053064#include <ol_txrx_osif_api.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080065#include "hif.h"
Dustin Brown0f8dc3d2017-06-01 14:37:26 -070066#include "hif_unit_test_suspend.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080067#include "sme_power_save_api.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080068#include "wlan_policy_mgr_api.h"
Dhanashri Atreb08959a2016-03-01 17:28:03 -080069#include "cdp_txrx_flow_ctrl_v2.h"
Yuanyuan Liu13738502016-04-06 17:41:37 -070070#include "pld_common.h"
Rajeev Kumar9bb2e852016-09-24 12:29:25 -070071#include "wlan_hdd_driver_ops.h"
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +053072#include <wlan_logging_sock_svc.h>
Krunal Sonid32c6bc2016-10-18 18:00:21 -070073#include "scheduler_api.h"
yeshwanth sriram guntuka310b3ac2016-11-15 23:25:26 +053074#include "cds_utils.h"
Hanumanth Reddy Pothula3def8942017-10-05 16:19:36 +053075#include "wlan_hdd_packet_filter_api.h"
Arunk Khandavallif0c0d762017-12-07 10:18:50 +053076#include "wlan_cfg80211_scan.h"
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +053077#include "wlan_ipa_ucfg_api.h"
Naveen Rawate8b1b822018-01-30 09:46:16 -080078#include <wlan_cfg80211_mc_cp_stats.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080079
80/* Preprocessor definitions and constants */
Yue Ma5fe30dd2017-05-02 15:47:40 -070081#ifdef QCA_WIFI_NAPIER_EMULATION
82#define HDD_SSR_BRING_UP_TIME 3000000
83#else
Yue Ma4ea4f052015-10-27 12:25:27 -070084#define HDD_SSR_BRING_UP_TIME 30000
Yue Ma5fe30dd2017-05-02 15:47:40 -070085#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080086
87/* Type declarations */
88
Abhishek Singhbaea27d2016-04-27 13:29:30 +053089#ifdef FEATURE_WLAN_DIAG_SUPPORT
Abhishek Singhbaea27d2016-04-27 13:29:30 +053090void hdd_wlan_suspend_resume_event(uint8_t state)
91{
92 WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend);
93 qdf_mem_zero(&suspend_state, sizeof(suspend_state));
94
95 suspend_state.state = state;
96 WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
97}
Abhishek Singh4aad0f72016-04-27 13:43:29 +053098
99/**
100 * hdd_wlan_offload_event()- send offloads event
101 * @type: offload type
102 * @state: enabled or disabled
103 *
104 * This Function send offloads enable/disable diag event
105 *
106 * Return: void.
107 */
108
109void hdd_wlan_offload_event(uint8_t type, uint8_t state)
110{
111 WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req);
112 qdf_mem_zero(&host_offload, sizeof(host_offload));
113
114 host_offload.offload_type = type;
115 host_offload.state = state;
116
117 WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ);
118}
Abhishek Singhbaea27d2016-04-27 13:29:30 +0530119#endif
120
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800121/**
Mukul Sharma3d36c392017-01-18 18:39:12 +0530122 * hdd_enable_gtk_offload() - enable GTK offload
123 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800124 *
Mukul Sharma3d36c392017-01-18 18:39:12 +0530125 * Central function to enable GTK offload.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800126 *
127 * Return: nothing
128 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700129static void hdd_enable_gtk_offload(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800130{
Mukul Sharma3d36c392017-01-18 18:39:12 +0530131 QDF_STATUS status;
Jeff Johnson4f7f7c62017-10-05 08:53:41 -0700132
Mukul Sharma3d36c392017-01-18 18:39:12 +0530133 status = pmo_ucfg_enable_gtk_offload_in_fwr(adapter->hdd_vdev);
134 if (status != QDF_STATUS_SUCCESS)
135 hdd_info("Failed to enable gtk offload");
136}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800137
Mukul Sharma3d36c392017-01-18 18:39:12 +0530138/**
139 * hdd_disable_gtk_offload() - disable GTK offload
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700140 * @adapter: pointer to the adapter
Mukul Sharma3d36c392017-01-18 18:39:12 +0530141 *
142 * Central function to disable GTK offload.
143 *
144 * Return: nothing
145 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700146static void hdd_disable_gtk_offload(struct hdd_adapter *adapter)
Mukul Sharma3d36c392017-01-18 18:39:12 +0530147{
148 struct pmo_gtk_rsp_req gtk_rsp_request;
149 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800150
Mukul Sharma3d36c392017-01-18 18:39:12 +0530151 /* ensure to get gtk rsp first before disable it*/
152 gtk_rsp_request.callback =
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530153 wlan_hdd_cfg80211_update_replay_counter_cb;
Mukul Sharma3d36c392017-01-18 18:39:12 +0530154 /* Passing as void* as PMO does not know legacy HDD adapter type */
155 gtk_rsp_request.callback_context =
156 (void *)adapter;
157 status = pmo_ucfg_get_gtk_rsp(adapter->hdd_vdev,
158 &gtk_rsp_request);
159 if (status != QDF_STATUS_SUCCESS) {
160 hdd_err("Failed to send get gtk rsp status:%d", status);
161 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800162 }
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800163 hdd_debug("send get_gtk_rsp successful");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530164 status = pmo_ucfg_disable_gtk_offload_in_fwr(adapter->hdd_vdev);
165 if (status != QDF_STATUS_SUCCESS)
166 hdd_info("Failed to disable gtk offload");
167
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800168}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800169
Qiwei Cai1083f5b2018-07-02 19:10:11 +0800170#ifdef WLAN_NS_OFFLOAD
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800171/**
172 * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function
173 * @nb: notifier block that was registered with the kernel
174 * @data: (unused) generic data that was registered with the kernel
175 * @arg: (unused) generic argument that was registered with the kernel
176 *
177 * This is a callback function that is registered with the kernel via
178 * register_inet6addr_notifier() which allows the driver to be
179 * notified when there is an IPv6 address change.
180 *
181 * Return: NOTIFY_DONE to indicate we don't care what happens with
182 * other callbacks
183 */
184static int __wlan_hdd_ipv6_changed(struct notifier_block *nb,
Dustin Brownf13b8c32017-05-19 17:23:08 -0700185 unsigned long data, void *arg)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800186{
187 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
188 struct net_device *ndev = ifa->idev->dev;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700189 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700190 struct hdd_context *hdd_ctx;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700191 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800192
Dustin Brownfdf17c12018-03-14 12:55:34 -0700193 hdd_enter_dev(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530194
Dustin Brownf13b8c32017-05-19 17:23:08 -0700195 errno = hdd_validate_adapter(adapter);
196 if (errno)
197 goto exit;
198
199 if (adapter->dev == ndev &&
200 (adapter->device_mode == QDF_STA_MODE ||
201 adapter->device_mode == QDF_P2P_CLIENT_MODE ||
202 adapter->device_mode == QDF_NDI_MODE)) {
203 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
204 errno = wlan_hdd_validate_context(hdd_ctx);
205 if (errno)
206 goto exit;
207
Nachiket Kukadec9045fe2017-06-19 15:14:43 +0530208 /* Ignore if the interface is down */
209 if (!(ndev->flags & IFF_UP)) {
210 hdd_err("Rcvd change addr request on %s(flags 0x%X)",
211 ndev->name, ndev->flags);
212 hdd_err("NETDEV Interface is down, ignoring...");
213 goto exit;
214 }
215
Dustin Brownf13b8c32017-05-19 17:23:08 -0700216 hdd_debug("invoking sme_dhcp_done_ind");
Jeff Johnson2954ded2018-06-13 16:34:49 -0700217 sme_dhcp_done_ind(hdd_ctx->mac_handle, adapter->session_id);
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700218 schedule_work(&adapter->ipv6_notifier_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800219 }
220
Dustin Brownf13b8c32017-05-19 17:23:08 -0700221exit:
Dustin Browne74003f2018-03-14 12:51:58 -0700222 hdd_exit();
Dustin Brownf13b8c32017-05-19 17:23:08 -0700223
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800224 return NOTIFY_DONE;
225}
226
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800227int wlan_hdd_ipv6_changed(struct notifier_block *nb,
228 unsigned long data, void *arg)
229{
230 int ret;
231
232 cds_ssr_protect(__func__);
233 ret = __wlan_hdd_ipv6_changed(nb, data, arg);
234 cds_ssr_unprotect(__func__);
235
236 return ret;
237}
238
239/**
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530240 * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses
241 * @idev: pointer to net device
242 * @ipv6addr: destination array to fill IPv6 addresses
243 * @ipv6addr_type: IPv6 Address type
244 * @count: number of IPv6 addresses
245 *
246 * This is the IPv6 utility function to populate unicast addresses.
247 *
248 * Return: 0 on success, error number otherwise.
249 */
250static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
251 uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN],
252 uint8_t *ipv6addr_type, uint32_t *count)
253{
254 struct inet6_ifaddr *ifa;
255 struct list_head *p;
256 uint32_t scope;
257
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700258 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530259 list_for_each(p, &idev->addr_list) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530260 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700261 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530262 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700263 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530264 ifa = list_entry(p, struct inet6_ifaddr, if_list);
265 if (ifa->flags & IFA_F_DADFAILED)
266 continue;
267 scope = ipv6_addr_src_scope(&ifa->addr);
268 switch (scope) {
269 case IPV6_ADDR_SCOPE_GLOBAL:
270 case IPV6_ADDR_SCOPE_LINKLOCAL:
271 qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
272 sizeof(ifa->addr.s6_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530273 ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE;
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800274 hdd_debug("Index %d scope = %s UC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530275 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
276 "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
277 *count += 1;
278 break;
279 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800280 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530281 }
282 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700283
284 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530285 return 0;
286}
287
288/**
289 * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses
290 * @idev: pointer to net device
291 * @ipv6addr: destination array to fill IPv6 addresses
292 * @ipv6addr_type: IPv6 Address type
293 * @count: number of IPv6 addresses
294 *
295 * This is the IPv6 utility function to populate anycast addresses.
296 *
297 * Return: 0 on success, error number otherwise.
298 */
299static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
300 uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN],
301 uint8_t *ipv6addr_type, uint32_t *count)
302{
303 struct ifacaddr6 *ifaca;
304 uint32_t scope;
305
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700306 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530307 for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530308 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700309 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530310 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700311 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530312 /* For anycast addr no DAD */
313 scope = ipv6_addr_src_scope(&ifaca->aca_addr);
314 switch (scope) {
315 case IPV6_ADDR_SCOPE_GLOBAL:
316 case IPV6_ADDR_SCOPE_LINKLOCAL:
317 qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
318 sizeof(ifaca->aca_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530319 ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE;
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800320 hdd_debug("Index %d scope = %s AC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530321 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
322 "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
323 *count += 1;
324 break;
325 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800326 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530327 }
328 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700329
330 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530331 return 0;
332}
333
Jeff Johnson75b737d2017-08-29 14:24:41 -0700334void hdd_enable_ns_offload(struct hdd_adapter *adapter,
Dustin Brownc1cdb712018-06-11 15:42:17 -0700335 enum pmo_offload_trigger trigger)
Dustin Brown2444ee62016-09-06 17:20:36 -0700336{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700337 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530338 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
Dustin Brownc1cdb712018-06-11 15:42:17 -0700339 struct inet6_dev *in6_dev;
340 struct pmo_ns_req *ns_req;
341 QDF_STATUS status;
342 int errno;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530343
Dustin Brown491d54b2018-03-14 12:39:11 -0700344 hdd_enter();
Dustin Brownc1cdb712018-06-11 15:42:17 -0700345
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530346 if (!psoc) {
347 hdd_err("psoc is NULL");
348 goto out;
349 }
Dustin Brown2444ee62016-09-06 17:20:36 -0700350
351 in6_dev = __in6_dev_get(adapter->dev);
352 if (NULL == in6_dev) {
353 hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530354 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700355 }
356
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530357 ns_req = qdf_mem_malloc(sizeof(*ns_req));
358 if (!ns_req) {
359 hdd_err("fail to allocate ns_req");
360 goto out;
361 }
362
363 ns_req->psoc = psoc;
Jeff Johnson1b780e42017-10-31 14:11:45 -0700364 ns_req->vdev_id = adapter->session_id;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530365 ns_req->trigger = trigger;
366 ns_req->count = 0;
367
Dustin Brown2444ee62016-09-06 17:20:36 -0700368 /* Unicast Addresses */
Dustin Brownc1cdb712018-06-11 15:42:17 -0700369 errno = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
370 ns_req->ipv6_addr_type, &ns_req->count);
371 if (errno) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530372 hdd_disable_ns_offload(adapter, trigger);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530373 hdd_debug("Max supported addresses: disabling NS offload");
Dustin Brownc1cdb712018-06-11 15:42:17 -0700374 goto free_req;
Dustin Brown2444ee62016-09-06 17:20:36 -0700375 }
376
377 /* Anycast Addresses */
Dustin Brownc1cdb712018-06-11 15:42:17 -0700378 errno = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
379 ns_req->ipv6_addr_type, &ns_req->count);
380 if (errno) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530381 hdd_disable_ns_offload(adapter, trigger);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530382 hdd_debug("Max supported addresses: disabling NS offload");
Dustin Brownc1cdb712018-06-11 15:42:17 -0700383 goto free_req;
Dustin Brown2444ee62016-09-06 17:20:36 -0700384 }
385
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530386 /* cache ns request */
387 status = pmo_ucfg_cache_ns_offload_req(ns_req);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700388 if (QDF_IS_STATUS_ERROR(status)) {
389 hdd_err("Failed to cache ns request; status:%d", status);
390 goto free_req;
Dustin Brown2444ee62016-09-06 17:20:36 -0700391 }
392
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530393 /* enable ns request */
394 status = pmo_ucfg_enable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700395 if (QDF_IS_STATUS_ERROR(status)) {
396 hdd_err("Failed to enable ns offload; status:%d", status);
397 goto free_req;
398 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530399
Dustin Brownc1cdb712018-06-11 15:42:17 -0700400 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
401
402free_req:
403 qdf_mem_free(ns_req);
404
405out:
406 hdd_exit();
Dustin Brown2444ee62016-09-06 17:20:36 -0700407}
408
Jeff Johnson75b737d2017-08-29 14:24:41 -0700409void hdd_disable_ns_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530410 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800411{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530412 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800413
Dustin Brown491d54b2018-03-14 12:39:11 -0700414 hdd_enter();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530415 status = pmo_ucfg_flush_ns_offload_req(adapter->hdd_vdev);
416 if (status != QDF_STATUS_SUCCESS) {
417 hdd_err("Failed to flush NS Offload");
418 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800419 }
420
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530421 status = pmo_ucfg_disable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
422 if (status != QDF_STATUS_SUCCESS)
423 hdd_err("Failed to disable NS Offload");
Dustin Brown2444ee62016-09-06 17:20:36 -0700424 else
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530425 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD,
426 SIR_OFFLOAD_DISABLE);
427out:
Dustin Browne74003f2018-03-14 12:51:58 -0700428 hdd_exit();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530429
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800430}
431
432/**
433 * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function
434 * @work: registered work item
435 *
436 * This function performs the work initially trigged by a callback
437 * from the IPv6 netdev notifier. Since this means there has been a
438 * change in IPv6 state for the interface, the NS offload is
439 * reconfigured.
440 *
441 * Return: None
442 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700443static void __hdd_ipv6_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800444{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700445 struct hdd_context *hdd_ctx;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700446 struct hdd_adapter *adapter;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700447 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800448
Dustin Brown491d54b2018-03-14 12:39:11 -0700449 hdd_enter();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800450
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700451 adapter = container_of(work, struct hdd_adapter, ipv6_notifier_work);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700452 errno = hdd_validate_adapter(adapter);
453 if (errno)
454 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800455
Dustin Brownf13b8c32017-05-19 17:23:08 -0700456 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
457 errno = wlan_hdd_validate_context(hdd_ctx);
458 if (errno)
459 goto exit;
460
461 hdd_enable_ns_offload(adapter, pmo_ipv6_change_notify);
462
463exit:
Dustin Browne74003f2018-03-14 12:51:58 -0700464 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800465}
466
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800467void hdd_ipv6_notifier_work_queue(struct work_struct *work)
468{
469 cds_ssr_protect(__func__);
470 __hdd_ipv6_notifier_work_queue(work);
471 cds_ssr_unprotect(__func__);
472}
Qiwei Cai1083f5b2018-07-02 19:10:11 +0800473#endif /* WLAN_NS_OFFLOAD */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474
Jeff Johnson75b737d2017-08-29 14:24:41 -0700475static void hdd_enable_hw_filter(struct hdd_adapter *adapter)
Dustin Brown1224e212017-05-12 14:02:12 -0700476{
477 QDF_STATUS status;
478
Dustin Brown491d54b2018-03-14 12:39:11 -0700479 hdd_enter();
Dustin Brown1224e212017-05-12 14:02:12 -0700480
481 status = pmo_ucfg_enable_hw_filter_in_fwr(adapter->hdd_vdev);
482 if (status != QDF_STATUS_SUCCESS)
483 hdd_info("Failed to enable hardware filter");
484
Dustin Browne74003f2018-03-14 12:51:58 -0700485 hdd_exit();
Dustin Brown1224e212017-05-12 14:02:12 -0700486}
487
Jeff Johnson75b737d2017-08-29 14:24:41 -0700488static void hdd_disable_hw_filter(struct hdd_adapter *adapter)
Dustin Brown1224e212017-05-12 14:02:12 -0700489{
490 QDF_STATUS status;
491
Dustin Brown491d54b2018-03-14 12:39:11 -0700492 hdd_enter();
Dustin Brown1224e212017-05-12 14:02:12 -0700493
494 status = pmo_ucfg_disable_hw_filter_in_fwr(adapter->hdd_vdev);
495 if (status != QDF_STATUS_SUCCESS)
496 hdd_info("Failed to disable hardware filter");
497
Dustin Browne74003f2018-03-14 12:51:58 -0700498 hdd_exit();
Dustin Brown1224e212017-05-12 14:02:12 -0700499}
500
Jeff Johnson75b737d2017-08-29 14:24:41 -0700501void hdd_enable_host_offloads(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530502 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800503{
Dustin Brown491d54b2018-03-14 12:39:11 -0700504 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530505
Rajeev Kumarec1194d2017-11-16 17:30:01 -0800506 if (!ucfg_pmo_is_vdev_supports_offload(adapter->hdd_vdev)) {
Dustin Brownc1cdb712018-06-11 15:42:17 -0700507 hdd_debug("offload is not supported on vdev opmode %d",
508 adapter->device_mode);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530509 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800510 }
511
Rajeev Kumar9084cc82017-10-31 14:32:08 -0700512 if (!ucfg_pmo_is_vdev_connected(adapter->hdd_vdev)) {
Dustin Brownc1cdb712018-06-11 15:42:17 -0700513 hdd_debug("offload is not supported on disconnected vdevs");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530514 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800515 }
516
Dustin Brownc1cdb712018-06-11 15:42:17 -0700517 hdd_debug("enable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530518 hdd_enable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530519 hdd_enable_arp_offload(adapter, trigger);
520 hdd_enable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530521 hdd_enable_mc_addr_filtering(adapter, trigger);
Dustin Brown1224e212017-05-12 14:02:12 -0700522 hdd_enable_hw_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530523out:
Dustin Browne74003f2018-03-14 12:51:58 -0700524 hdd_exit();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530525
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800526}
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530527
Jeff Johnson75b737d2017-08-29 14:24:41 -0700528void hdd_disable_host_offloads(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530529 enum pmo_offload_trigger trigger)
530{
Dustin Brown491d54b2018-03-14 12:39:11 -0700531 hdd_enter();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530532
Rajeev Kumarec1194d2017-11-16 17:30:01 -0800533 if (!ucfg_pmo_is_vdev_supports_offload(adapter->hdd_vdev)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530534 hdd_info("offload is not supported on this vdev opmode: %d",
535 adapter->device_mode);
536 goto out;
537 }
538
Rajeev Kumar9084cc82017-10-31 14:32:08 -0700539 if (!ucfg_pmo_is_vdev_connected(adapter->hdd_vdev)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530540 hdd_info("vdev is not connected");
541 goto out;
542 }
543
Dustin Brownc1cdb712018-06-11 15:42:17 -0700544 hdd_debug("disable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530545 hdd_disable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530546 hdd_disable_arp_offload(adapter, trigger);
547 hdd_disable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530548 hdd_disable_mc_addr_filtering(adapter, trigger);
Dustin Brown1224e212017-05-12 14:02:12 -0700549 hdd_disable_hw_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530550out:
Dustin Browne74003f2018-03-14 12:51:58 -0700551 hdd_exit();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530552
553}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800554
555/**
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800556 * hdd_lookup_ifaddr() - Lookup interface address data by name
557 * @adapter: the adapter whose name should be searched for
558 *
559 * return in_ifaddr pointer on success, NULL for failure
560 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700561static struct in_ifaddr *hdd_lookup_ifaddr(struct hdd_adapter *adapter)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800562{
563 struct in_ifaddr *ifa;
564 struct in_device *in_dev;
565
566 if (!adapter) {
567 hdd_err("adapter is null");
568 return NULL;
569 }
570
571 in_dev = __in_dev_get_rtnl(adapter->dev);
572 if (!in_dev) {
573 hdd_err("Failed to get in_device");
574 return NULL;
575 }
576
577 /* lookup address data by interface name */
578 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
579 if (!strcmp(adapter->dev->name, ifa->ifa_label))
580 return ifa;
581 }
582
583 return NULL;
584}
585
586/**
587 * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address
588 * @adapter: the adapter whose IPv4 address is desired
589 * @ipv4_addr: the address of the array to copy the IPv4 address into
590 *
591 * return: zero for success; non-zero for failure
592 */
Jeff Johnsond6d1f632017-10-06 20:06:10 -0700593static int hdd_populate_ipv4_addr(struct hdd_adapter *adapter,
594 uint8_t *ipv4_addr)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800595{
596 struct in_ifaddr *ifa;
597 int i;
598
599 if (!adapter) {
600 hdd_err("adapter is null");
601 return -EINVAL;
602 }
603
604 if (!ipv4_addr) {
605 hdd_err("ipv4_addr is null");
606 return -EINVAL;
607 }
608
609 ifa = hdd_lookup_ifaddr(adapter);
610 if (!ifa || !ifa->ifa_local) {
611 hdd_err("ipv4 address not found");
612 return -EINVAL;
613 }
614
615 /* convert u32 to byte array */
616 for (i = 0; i < 4; i++)
617 ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff;
618
619 return 0;
620}
621
622/**
623 * hdd_set_grat_arp_keepalive() - Enable grat APR keepalive
624 * @adapter: the HDD adapter to configure
625 *
626 * This configures gratuitous APR keepalive based on the adapter's current
627 * connection information, specifically IPv4 address and BSSID
628 *
629 * return: zero for success, non-zero for failure
630 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700631static int hdd_set_grat_arp_keepalive(struct hdd_adapter *adapter)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800632{
633 QDF_STATUS status;
634 int exit_code;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700635 struct hdd_context *hdd_ctx;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700636 struct hdd_station_ctx *sta_ctx;
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800637 tSirKeepAliveReq req = {
638 .packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP,
Dustin Brownce5b3d32018-01-17 15:07:38 -0800639 .dest_macaddr = QDF_MAC_ADDR_BCAST_INIT,
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800640 };
641
642 if (!adapter) {
643 hdd_err("adapter is null");
644 return -EINVAL;
645 }
646
647 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
648 if (!hdd_ctx) {
649 hdd_err("hdd_ctx is null");
650 return -EINVAL;
651 }
652
653 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
654 if (!sta_ctx) {
655 hdd_err("sta_ctx is null");
656 return -EINVAL;
657 }
658
659 exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr);
660 if (exit_code) {
661 hdd_err("Failed to populate ipv4 address");
662 return exit_code;
663 }
664
Dustin Brown6b4643d2017-02-09 12:19:28 -0800665 /* according to RFC5227, sender/target ip address should be the same */
666 qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr,
667 sizeof(req.destIpv4Addr));
668
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800669 qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssId);
670 req.timePeriod = hdd_ctx->config->infraStaKeepAlivePeriod;
Jeff Johnson1b780e42017-10-31 14:11:45 -0700671 req.sessionId = adapter->session_id;
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800672
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800673 hdd_debug("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u",
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800674 req.hostIpv4Addr[0], req.hostIpv4Addr[1],
675 req.hostIpv4Addr[2], req.hostIpv4Addr[3]);
676
Jeff Johnson2954ded2018-06-13 16:34:49 -0700677 status = sme_set_keep_alive(hdd_ctx->mac_handle, req.sessionId, &req);
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800678 if (QDF_IS_STATUS_ERROR(status)) {
679 hdd_err("Failed to set keepalive");
680 return qdf_status_to_os_return(status);
681 }
682
683 return 0;
684}
685
686/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800687 * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function
688 * @work: registered work item
689 *
690 * This function performs the work initially trigged by a callback
691 * from the IPv4 netdev notifier. Since this means there has been a
692 * change in IPv4 state for the interface, the ARP offload is
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530693 * reconfigured. Also, Updates the HLP IE info with IP address info
694 * to fw if LFR3 is enabled
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800695 *
696 * Return: None
697 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700698static void __hdd_ipv4_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800699{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700700 struct hdd_context *hdd_ctx;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700701 struct hdd_adapter *adapter;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700702 int errno;
Jeff Johnson61b5e982018-03-15 11:33:31 -0700703 struct csr_roam_profile *roam_profile;
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530704 struct in_ifaddr *ifa;
Dustin Brownb6b0f182017-03-08 13:08:27 -0800705
Dustin Brown491d54b2018-03-14 12:39:11 -0700706 hdd_enter();
Dustin Brownb6b0f182017-03-08 13:08:27 -0800707
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700708 adapter = container_of(work, struct hdd_adapter, ipv4_notifier_work);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700709 errno = hdd_validate_adapter(adapter);
710 if (errno)
711 goto exit;
Dustin Brownb6b0f182017-03-08 13:08:27 -0800712
713 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700714 errno = wlan_hdd_validate_context(hdd_ctx);
715 if (errno)
716 goto exit;
717
718 hdd_enable_arp_offload(adapter, pmo_ipv4_change_notify);
719
Dustin Brownb6b0f182017-03-08 13:08:27 -0800720 if (hdd_ctx->config->sta_keepalive_method == HDD_STA_KEEPALIVE_GRAT_ARP)
721 hdd_set_grat_arp_keepalive(adapter);
722
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530723 hdd_debug("FILS Roaming support: %d",
724 hdd_ctx->is_fils_roaming_supported);
Jeff Johnsona0c1ca72018-03-18 14:52:03 -0700725 roam_profile = hdd_roam_profile(adapter);
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530726
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530727 ifa = hdd_lookup_ifaddr(adapter);
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530728 if (ifa && hdd_ctx->is_fils_roaming_supported)
Jeff Johnson2954ded2018-06-13 16:34:49 -0700729 sme_send_hlp_ie_info(hdd_ctx->mac_handle, adapter->session_id,
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530730 roam_profile, ifa->ifa_local);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700731exit:
Dustin Browne74003f2018-03-14 12:51:58 -0700732 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800733}
734
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800735void hdd_ipv4_notifier_work_queue(struct work_struct *work)
736{
737 cds_ssr_protect(__func__);
738 __hdd_ipv4_notifier_work_queue(work);
739 cds_ssr_unprotect(__func__);
740}
741
742/**
743 * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function
744 * @nb: notifier block that was registered with the kernel
745 * @data: (unused) generic data that was registered with the kernel
746 * @arg: (unused) generic argument that was registered with the kernel
747 *
748 * This is a callback function that is registered with the kernel via
749 * register_inetaddr_notifier() which allows the driver to be
750 * notified when there is an IPv4 address change.
751 *
752 * Return: NOTIFY_DONE to indicate we don't care what happens with
753 * other callbacks
754 */
755static int __wlan_hdd_ipv4_changed(struct notifier_block *nb,
756 unsigned long data, void *arg)
757{
758 struct in_ifaddr *ifa = (struct in_ifaddr *)arg;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800759 struct net_device *ndev = ifa->ifa_dev->dev;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700760 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700761 struct hdd_context *hdd_ctx;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700762 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800763
Dustin Brownfdf17c12018-03-14 12:55:34 -0700764 hdd_enter_dev(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530765
Dustin Brownf13b8c32017-05-19 17:23:08 -0700766 errno = hdd_validate_adapter(adapter);
767 if (errno)
768 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800769
Dustin Brownf13b8c32017-05-19 17:23:08 -0700770 if (adapter->dev == ndev &&
771 (adapter->device_mode == QDF_STA_MODE ||
772 adapter->device_mode == QDF_P2P_CLIENT_MODE ||
773 adapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800774
Dustin Brownf13b8c32017-05-19 17:23:08 -0700775 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
776 errno = wlan_hdd_validate_context(hdd_ctx);
777 if (errno)
778 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800779
Nachiket Kukadec9045fe2017-06-19 15:14:43 +0530780 /* Ignore if the interface is down */
781 if (!(ndev->flags & IFF_UP)) {
782 hdd_err("Rcvd change addr request on %s(flags 0x%X)",
783 ndev->name, ndev->flags);
784 hdd_err("NETDEV Interface is down, ignoring...");
785 goto exit;
786 }
Padma, Santhosh Kumar8392fb42017-03-17 12:35:27 +0530787 hdd_debug("invoking sme_dhcp_done_ind");
Jeff Johnson2954ded2018-06-13 16:34:49 -0700788 sme_dhcp_done_ind(hdd_ctx->mac_handle, adapter->session_id);
Abhishek Singhca408032016-09-13 15:26:12 +0530789
Dustin Brownf13b8c32017-05-19 17:23:08 -0700790 if (!hdd_ctx->config->fhostArpOffload) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800791 hdd_debug("Offload not enabled ARPOffload=%d",
Dustin Brownf13b8c32017-05-19 17:23:08 -0700792 hdd_ctx->config->fhostArpOffload);
793 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800794 }
795
Dustin Brownf13b8c32017-05-19 17:23:08 -0700796 ifa = hdd_lookup_ifaddr(adapter);
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800797 if (ifa && ifa->ifa_local)
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700798 schedule_work(&adapter->ipv4_notifier_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800799 }
Dustin Brownf13b8c32017-05-19 17:23:08 -0700800
801exit:
Dustin Browne74003f2018-03-14 12:51:58 -0700802 hdd_exit();
Dustin Brownf13b8c32017-05-19 17:23:08 -0700803
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800804 return NOTIFY_DONE;
805}
806
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800807int wlan_hdd_ipv4_changed(struct notifier_block *nb,
808 unsigned long data, void *arg)
809{
810 int ret;
811
812 cds_ssr_protect(__func__);
813 ret = __wlan_hdd_ipv4_changed(nb, data, arg);
814 cds_ssr_unprotect(__func__);
815
816 return ret;
817}
818
819/**
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530820 * hdd_get_ipv4_local_interface() - get ipv4 local interafce from iface list
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700821 * @adapter: Adapter context for which ARP offload is to be configured
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800822 *
823 * Return:
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530824 * ifa - on successful operation,
825 * NULL - on failure of operation
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800826 */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530827static struct in_ifaddr *hdd_get_ipv4_local_interface(
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700828 struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800829{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530830 struct in_ifaddr **ifap = NULL;
831 struct in_ifaddr *ifa = NULL;
832 struct in_device *in_dev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800833
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700834 in_dev = __in_dev_get_rtnl(adapter->dev);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530835 if (in_dev) {
836 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
837 ifap = &ifa->ifa_next) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700838 if (!strcmp(adapter->dev->name, ifa->ifa_label)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530839 /* if match break */
840 return ifa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800841 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800842 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530843 }
844 ifa = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800845
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530846 return ifa;
847}
848
Jeff Johnson75b737d2017-08-29 14:24:41 -0700849void hdd_enable_arp_offload(struct hdd_adapter *adapter,
Dustin Brownc1cdb712018-06-11 15:42:17 -0700850 enum pmo_offload_trigger trigger)
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530851{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700852 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530853 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
854 QDF_STATUS status;
Dustin Brownc1cdb712018-06-11 15:42:17 -0700855 struct pmo_arp_req *arp_req;
856 struct in_ifaddr *ifa;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530857
Dustin Brown491d54b2018-03-14 12:39:11 -0700858 hdd_enter();
Dustin Brownc1cdb712018-06-11 15:42:17 -0700859
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530860 arp_req = qdf_mem_malloc(sizeof(*arp_req));
861 if (!arp_req) {
862 hdd_err("cannot allocate arp_req");
863 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800864 }
Jeff Johnson68755312017-02-10 11:46:55 -0800865
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530866 arp_req->psoc = psoc;
Jeff Johnson1b780e42017-10-31 14:11:45 -0700867 arp_req->vdev_id = adapter->session_id;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530868 arp_req->trigger = trigger;
Jeff Johnson68755312017-02-10 11:46:55 -0800869
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530870 ifa = hdd_get_ipv4_local_interface(adapter);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700871 if (!ifa || !ifa->ifa_local) {
Dustin Brown5e89ef82018-03-14 11:50:23 -0700872 hdd_info("IP Address is not assigned");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530873 status = QDF_STATUS_NOT_INITIALIZED;
Dustin Brownc1cdb712018-06-11 15:42:17 -0700874 goto free_req;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530875 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530876
Dustin Brownc1cdb712018-06-11 15:42:17 -0700877 arp_req->ipv4_addr = (uint32_t)ifa->ifa_local;
878
879 status = pmo_ucfg_cache_arp_offload_req(arp_req);
880 if (QDF_IS_STATUS_ERROR(status)) {
881 hdd_err("failed to cache arp offload request");
882 goto free_req;
883 }
884
885 status = pmo_ucfg_enable_arp_offload_in_fwr(adapter->hdd_vdev, trigger);
886 if (QDF_IS_STATUS_ERROR(status)) {
887 hdd_err("failed to configure arp offload in firmware");
888 goto free_req;
889 }
890
891 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD, PMO_OFFLOAD_ENABLE);
892
893free_req:
894 qdf_mem_free(arp_req);
895
896out:
897 hdd_exit();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530898}
899
Jeff Johnson75b737d2017-08-29 14:24:41 -0700900void hdd_disable_arp_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530901 enum pmo_offload_trigger trigger)
902{
903 QDF_STATUS status;
904
Dustin Brown491d54b2018-03-14 12:39:11 -0700905 hdd_enter();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530906 status = pmo_ucfg_flush_arp_offload_req(adapter->hdd_vdev);
907 if (status != QDF_STATUS_SUCCESS) {
908 hdd_err("Failed to flush arp Offload");
909 goto out;
Jeff Johnson68755312017-02-10 11:46:55 -0800910 }
911
Jeff Johnsond6d1f632017-10-06 20:06:10 -0700912 status = pmo_ucfg_disable_arp_offload_in_fwr(adapter->hdd_vdev,
913 trigger);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530914 if (status == QDF_STATUS_SUCCESS)
915 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD,
916 PMO_OFFLOAD_DISABLE);
917 else
918 hdd_info("fail to disable arp offload");
919out:
Dustin Browne74003f2018-03-14 12:51:58 -0700920 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800921}
922
Jeff Johnson75b737d2017-08-29 14:24:41 -0700923void hdd_enable_mc_addr_filtering(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530924 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800925{
Jeff Johnson399c6272017-08-30 10:51:00 -0700926 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530927 QDF_STATUS status;
928 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929
Dustin Brown491d54b2018-03-14 12:39:11 -0700930 hdd_enter();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530931 if (wlan_hdd_validate_context(hdd_ctx))
932 goto out;
Ravi Joshi24477b72016-07-19 15:45:09 -0700933
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530934 status = pmo_ucfg_enable_mc_addr_filtering_in_fwr(psoc,
Jeff Johnson1b780e42017-10-31 14:11:45 -0700935 adapter->session_id, trigger);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700936 if (QDF_IS_STATUS_ERROR(status))
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530937 hdd_info("failed to enable mc list status %d", status);
938out:
Dustin Browne74003f2018-03-14 12:51:58 -0700939 hdd_exit();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530940
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800941}
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530942
Jeff Johnson75b737d2017-08-29 14:24:41 -0700943void hdd_disable_mc_addr_filtering(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530944 enum pmo_offload_trigger trigger)
945{
Jeff Johnson399c6272017-08-30 10:51:00 -0700946 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530947 QDF_STATUS status = QDF_STATUS_SUCCESS;
948 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
949
Dustin Brown491d54b2018-03-14 12:39:11 -0700950 hdd_enter();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530951 if (wlan_hdd_validate_context(hdd_ctx))
952 goto out;
953
954 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
Jeff Johnson1b780e42017-10-31 14:11:45 -0700955 adapter->session_id, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530956 if (status != QDF_STATUS_SUCCESS)
957 hdd_info("failed to disable mc list status %d", status);
Dustin Brown0f874482018-06-13 14:39:22 -0700958
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530959out:
Dustin Browne74003f2018-03-14 12:51:58 -0700960 hdd_exit();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530961}
962
963int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config)
964{
965 QDF_STATUS status;
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530966
Dustin Brown491d54b2018-03-14 12:39:11 -0700967 hdd_enter();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530968 status = pmo_ucfg_cache_mc_addr_list(mc_list_config);
Dustin Browne74003f2018-03-14 12:51:58 -0700969 hdd_exit();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530970
Dustin Brown0f874482018-06-13 14:39:22 -0700971 return qdf_status_to_os_return(status);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530972}
973
Jeff Johnson75b737d2017-08-29 14:24:41 -0700974void hdd_disable_and_flush_mc_addr_list(struct hdd_adapter *adapter,
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530975 enum pmo_offload_trigger trigger)
976{
Jeff Johnson399c6272017-08-30 10:51:00 -0700977 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530978 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
979 QDF_STATUS status = QDF_STATUS_SUCCESS;
980
Dustin Brown491d54b2018-03-14 12:39:11 -0700981 hdd_enter();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530982 /* disable mc list first */
983 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
Jeff Johnson1b780e42017-10-31 14:11:45 -0700984 adapter->session_id, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530985 if (status != QDF_STATUS_SUCCESS)
986 hdd_info("fail to disable mc list");
987
988 /* flush mc list */
Jeff Johnson1b780e42017-10-31 14:11:45 -0700989 status = pmo_ucfg_flush_mc_addr_list(psoc, adapter->session_id);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530990 if (status != QDF_STATUS_SUCCESS)
991 hdd_info("fail to flush mc list status %d", status);
Dustin Brown0f874482018-06-13 14:39:22 -0700992
Dustin Browne74003f2018-03-14 12:51:58 -0700993 hdd_exit();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530994
995 return;
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530996}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800997
998/**
Houston Hoffman7260ecb2015-10-05 18:43:07 -0700999 * hdd_update_conn_state_mask(): record info needed by wma_suspend_req
1000 * @adapter: adapter to get info from
1001 * @conn_state_mask: mask of connection info
1002 *
1003 * currently only need to send connection info.
1004 */
Jeff Johnsond6d1f632017-10-06 20:06:10 -07001005static void hdd_update_conn_state_mask(struct hdd_adapter *adapter,
1006 uint32_t *conn_state_mask)
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001007{
1008
1009 eConnectionState connState;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07001010 struct hdd_station_ctx *sta_ctx;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301011
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001012 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301013
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001014 connState = sta_ctx->conn_info.connState;
1015
1016 if (connState == eConnectionState_Associated ||
1017 connState == eConnectionState_IbssConnected)
Jeff Johnson1b780e42017-10-31 14:11:45 -07001018 *conn_state_mask |= (1 << adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001019}
1020
1021/**
1022 * hdd_suspend_wlan() - Driver suspend function
1023 * @callback: Callback function to invoke when driver is ready to suspend
1024 * @callbackContext: Context to pass back to @callback function
1025 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301026 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301028static int
1029hdd_suspend_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001030{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001031 struct hdd_context *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301032 QDF_STATUS status;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001033 struct hdd_adapter *adapter = NULL;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001034 uint32_t conn_state_mask = 0;
Jeff Johnson4f7f7c62017-10-05 08:53:41 -07001035
Jeff Johnsonc3273322016-07-06 15:28:17 -07001036 hdd_info("WLAN being suspended by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001037
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001038 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1039 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001040 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301041 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001042 }
1043
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301044 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001045 hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001046 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301047 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001048 }
1049
Dustin Brown920397d2017-12-13 16:27:50 -08001050 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson1b780e42017-10-31 14:11:45 -07001051 if (wlan_hdd_validate_session_id(adapter->session_id)) {
1052 hdd_err("invalid session id: %d", adapter->session_id);
Dustin Brown920397d2017-12-13 16:27:50 -08001053 continue;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301054 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001055
1056 /* stop all TX queues before suspend */
Dustin Brownc1cdb712018-06-11 15:42:17 -07001057 hdd_debug("Disabling queues for dev mode %s",
1058 hdd_device_mode_to_string(adapter->device_mode));
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001059 wlan_hdd_netif_queue_control(adapter,
Himanshu Agarwal865201d2017-04-12 15:45:31 +05301060 WLAN_STOP_ALL_NETIF_QUEUE,
1061 WLAN_CONTROL_PATH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001062
Hanumanth Reddy Pothula3def8942017-10-05 16:19:36 +05301063 if (adapter->device_mode == QDF_STA_MODE)
1064 status = hdd_enable_default_pkt_filters(adapter);
1065
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001066 /* Configure supported OffLoads */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001067 hdd_enable_host_offloads(adapter, pmo_apps_suspend);
1068 hdd_update_conn_state_mask(adapter, &conn_state_mask);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001069 }
1070
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001071 status = pmo_ucfg_psoc_user_space_suspend_req(hdd_ctx->hdd_psoc,
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301072 QDF_SYSTEM_SUSPEND);
1073 if (status != QDF_STATUS_SUCCESS)
1074 return -EAGAIN;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001075
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001076 hdd_ctx->hdd_wlan_suspended = true;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301077 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001078
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301079 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001080}
1081
1082/**
1083 * hdd_resume_wlan() - Driver resume function
1084 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301085 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001086 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301087static int hdd_resume_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001088{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001089 struct hdd_context *hdd_ctx;
Dustin Brownc1cdb712018-06-11 15:42:17 -07001090 struct hdd_adapter *adapter;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301091 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001092
Dustin Brown2d228232016-09-22 15:06:19 -07001093 hdd_info("WLAN being resumed by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001094
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001095 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1096 if (!hdd_ctx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001097 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301098 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001099 }
1100
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301101 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001102 hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001103 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301104 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105 }
1106
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001107 hdd_ctx->hdd_wlan_suspended = false;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301108 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001109
1110 /*loop through all adapters. Concurrency */
Dustin Brown920397d2017-12-13 16:27:50 -08001111 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson1b780e42017-10-31 14:11:45 -07001112 if (wlan_hdd_validate_session_id(adapter->session_id)) {
1113 hdd_err("invalid session id: %d", adapter->session_id);
Dustin Brown920397d2017-12-13 16:27:50 -08001114 continue;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301115 }
1116 /* Disable supported OffLoads */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001117 hdd_disable_host_offloads(adapter, pmo_apps_resume);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118
1119 /* wake the tx queues */
Dustin Brownc1cdb712018-06-11 15:42:17 -07001120 hdd_debug("Enabling queues for dev mode %s",
1121 hdd_device_mode_to_string(adapter->device_mode));
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001122 wlan_hdd_netif_queue_control(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001123 WLAN_WAKE_ALL_NETIF_QUEUE,
1124 WLAN_CONTROL_PATH);
1125
Hanumanth Reddy Pothula3def8942017-10-05 16:19:36 +05301126 if (adapter->device_mode == QDF_STA_MODE)
1127 status = hdd_disable_default_pkt_filters(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001128 }
Dustin Brown920397d2017-12-13 16:27:50 -08001129
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301130 ucfg_ipa_resume(hdd_ctx->hdd_pdev);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001131 status = pmo_ucfg_psoc_user_space_resume_req(hdd_ctx->hdd_psoc,
Dustin Brownc1cdb712018-06-11 15:42:17 -07001132 QDF_SYSTEM_SUSPEND);
1133 if (QDF_IS_STATUS_ERROR(status))
1134 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001135
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301136 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001137}
1138
Komal Seelam78ff65a2016-08-18 15:25:24 +05301139void hdd_svc_fw_shutdown_ind(struct device *dev)
1140{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001141 struct hdd_context *hdd_ctx;
Komal Seelam78ff65a2016-08-18 15:25:24 +05301142
1143 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1144
1145 hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
1146 WLAN_SVC_FW_SHUTDOWN_IND,
1147 NULL, 0) : 0;
1148}
1149
1150/**
Arun Khandavallicc544b32017-01-30 19:52:16 +05301151 * hdd_ssr_restart_sap() - restart sap on SSR
1152 * @hdd_ctx: hdd context
1153 *
1154 * Return: nothing
1155 */
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001156static void hdd_ssr_restart_sap(struct hdd_context *hdd_ctx)
Arun Khandavallicc544b32017-01-30 19:52:16 +05301157{
Jeff Johnson75b737d2017-08-29 14:24:41 -07001158 struct hdd_adapter *adapter;
Arun Khandavallicc544b32017-01-30 19:52:16 +05301159
Dustin Brown491d54b2018-03-14 12:39:11 -07001160 hdd_enter();
Arun Khandavallicc544b32017-01-30 19:52:16 +05301161
Dustin Brown920397d2017-12-13 16:27:50 -08001162 hdd_for_each_adapter(hdd_ctx, adapter) {
1163 if (adapter->device_mode == QDF_SAP_MODE) {
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001164 if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001165 hdd_debug("Restart prev SAP session");
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001166 wlan_hdd_start_sap(adapter, true);
1167 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05301168 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05301169 }
1170
Dustin Browne74003f2018-03-14 12:51:58 -07001171 hdd_exit();
Arun Khandavallicc544b32017-01-30 19:52:16 +05301172}
1173
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301174QDF_STATUS hdd_wlan_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001175{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001176 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001177 p_cds_sched_context cds_sched_context = NULL;
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001178 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001179
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001180 hdd_info("WLAN driver shutting down!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001181
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001182 /* Get the HDD context. */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001183 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1184 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001185 hdd_err("HDD context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301186 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001187 }
1188
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001189 policy_mgr_clear_concurrent_session_count(hdd_ctx->hdd_psoc);
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301190
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001191 hdd_debug("Invoking packetdump deregistration API");
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301192 wlan_deregister_txrx_packetdump();
jitiphilfb410612018-03-26 22:37:56 +05301193
1194 /*
1195 * After SSR, FW clear its txrx stats. In host,
1196 * as adapter is intact so those counts are still
1197 * available. Now if agains Set stats command comes,
1198 * then host will increment its counts start from its
1199 * last saved value, i.e., count before SSR, and FW will
1200 * increment its count from 0. This will finally sends a
1201 * mismatch of packet counts b/w host and FW to framework
1202 * that will create ambiquity. Therfore, Resetting the host
1203 * counts here so that after SSR both FW and host start
1204 * increment their counts from 0.
1205 */
1206 hdd_reset_all_adapters_connectivity_stats(hdd_ctx);
1207
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001208 hdd_reset_all_adapters(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001209
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301210 /* Flush cached rx frame queue */
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001211 if (soc)
1212 cdp_flush_cache_rx_queue(soc);
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301213
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301214 /* De-register the HDD callbacks */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001215 hdd_deregister_cb(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001216
1217 cds_sched_context = get_cds_sched_ctxt();
1218
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001219 if (hdd_ctx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001220 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001221 hdd_ctx->is_scheduler_suspended = false;
Jeff Johnson214671b2017-10-30 19:45:23 -07001222 hdd_ctx->is_wiphy_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001223 }
1224#ifdef QCA_CONFIG_SMP
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001225 if (true == hdd_ctx->is_ol_rx_thread_suspended) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001226 complete(&cds_sched_context->ol_resume_rx_event);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001227 hdd_ctx->is_ol_rx_thread_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001228 }
1229#endif
1230
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001231 hdd_bus_bandwidth_destroy(hdd_ctx);
Prashanth Bhattaab004382016-10-11 16:08:11 -07001232
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001233 hdd_wlan_stop_modules(hdd_ctx, false);
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301234
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001235 hdd_lpass_notify_stop(hdd_ctx);
Yuanyuan Liu3e918e52016-08-17 15:41:35 -07001236
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001237 wlan_objmgr_print_ref_all_objects_per_psoc(hdd_ctx->hdd_psoc);
Yue Ma2be12872017-06-02 13:06:58 -07001238
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001239 hdd_info("WLAN driver shutdown complete");
Yue Ma2be12872017-06-02 13:06:58 -07001240
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301241 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001242}
1243
Sen, Devendra154b3c42017-02-13 20:44:15 +05301244#ifdef FEATURE_WLAN_DIAG_SUPPORT
1245/**
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301246 * hdd_wlan_ssr_reinit_event()- send ssr reinit state
1247 *
1248 * This Function send send ssr reinit state diag event
1249 *
1250 * Return: void.
1251 */
Sen, Devendra154b3c42017-02-13 20:44:15 +05301252static void hdd_wlan_ssr_reinit_event(void)
1253{
1254 WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit);
1255 qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit));
1256 ssr_reinit.status = SSR_SUB_SYSTEM_REINIT;
1257 WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit,
1258 EVENT_WLAN_SSR_REINIT_SUBSYSTEM);
1259}
1260#else
1261static inline void hdd_wlan_ssr_reinit_event(void)
1262{
1263
1264}
1265#endif
1266
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001267/**
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301268 * hdd_send_default_scan_ies - send default scan ies to fw
1269 *
1270 * This function is used to send default scan ies to fw
1271 * in case of wlan re-init
1272 *
1273 * Return: void
1274 */
1275static void hdd_send_default_scan_ies(struct hdd_context *hdd_ctx)
1276{
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301277 struct hdd_adapter *adapter;
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301278
Dustin Brown920397d2017-12-13 16:27:50 -08001279 hdd_for_each_adapter(hdd_ctx, adapter) {
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301280 if (hdd_is_interface_up(adapter) &&
1281 (adapter->device_mode == QDF_STA_MODE ||
Hanumanth Reddy Pothula53dec122017-12-12 17:08:18 +05301282 adapter->device_mode == QDF_P2P_DEVICE_MODE) &&
1283 adapter->scan_info.default_scan_ies) {
Jeff Johnson2954ded2018-06-13 16:34:49 -07001284 sme_set_default_scan_ie(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001285 adapter->session_id,
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301286 adapter->scan_info.default_scan_ies,
1287 adapter->scan_info.default_scan_ies_len);
1288 }
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301289 }
1290}
1291
Arun Khandavallifae92942016-08-01 13:31:08 +05301292QDF_STATUS hdd_wlan_re_init(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001293{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001294 struct hdd_context *hdd_ctx = NULL;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001295 struct hdd_adapter *adapter;
Arun Khandavallifae92942016-08-01 13:31:08 +05301296 int ret;
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301297 bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001298
1299 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1300
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001301 /* Get the HDD context */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001302 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1303 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001304 hdd_err("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001305 goto err_re_init;
1306 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001307 bug_on_reinit_failure = hdd_ctx->config->bug_on_reinit_failure;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001308
Sourav Mohapatra92ea8d62018-02-05 10:03:10 +05301309 adapter = hdd_get_first_valid_adapter(hdd_ctx);
1310 if (!adapter)
1311 hdd_err("Failed to get adapter");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001312
Nirav Shahd21a2e32018-04-20 16:34:43 +05301313 hdd_dp_trace_init(hdd_ctx->config);
Nirav Shahcc1f1ae2016-04-26 11:41:29 +05301314
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001315 hdd_bus_bandwidth_init(hdd_ctx);
Prashanth Bhattaab004382016-10-11 16:08:11 -07001316
Arun Khandavallicc544b32017-01-30 19:52:16 +05301317
Dustin Browne7e71d32018-05-11 16:00:08 -07001318 ret = hdd_wlan_start_modules(hdd_ctx, true);
Arun Khandavallifae92942016-08-01 13:31:08 +05301319 if (ret) {
1320 hdd_err("Failed to start wlan after error");
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301321 goto err_re_init;
Arun Khandavallifae92942016-08-01 13:31:08 +05301322 }
1323
Ryan Hsuaadba072018-04-20 13:01:53 -07001324 hdd_update_hw_sw_info(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001325
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001326 wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
Wu Gao36717432016-11-21 15:09:48 +08001327 WLAN_SVC_FW_CRASHED_IND, NULL, 0);
1328
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001329 /* Restart all adapters */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001330 hdd_start_all_adapters(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001331
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001332 hdd_ctx->last_scan_reject_session_id = 0xFF;
1333 hdd_ctx->last_scan_reject_reason = 0;
1334 hdd_ctx->last_scan_reject_timestamp = 0;
1335 hdd_ctx->scan_reject_cnt = 0;
Sreelakshmi Konamkib53c6292017-03-01 13:13:23 +05301336
Selvaraj, Sridhar1c487562017-04-19 14:29:07 +05301337 hdd_set_roaming_in_progress(false);
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001338 complete(&adapter->roaming_comp_var);
Jeff Johnson59b19312017-11-02 21:14:33 -07001339 hdd_ctx->bt_coex_mode_set = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001340
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001341 /* Allow the phone to go to sleep */
1342 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05301343 /* set chip power save failure detected callback */
Jeff Johnson2954ded2018-06-13 16:34:49 -07001344 sme_set_chip_pwr_save_fail_cb(hdd_ctx->mac_handle,
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05301345 hdd_chip_pwr_save_fail_detected_cb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001346
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001347 hdd_lpass_notify_start(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001348
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301349 hdd_send_default_scan_ies(hdd_ctx);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001350 hdd_info("WLAN host driver reinitiation completed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001351 goto success;
1352
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001353err_re_init:
Rachit Kankane30807332018-06-27 18:39:36 +05301354 qdf_dp_trace_deinit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001355 /* Allow the phone to go to sleep */
1356 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301357 if (bug_on_reinit_failure)
1358 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001359 return -EPERM;
1360
1361success:
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001362 if (hdd_ctx->config->sap_internal_restart)
1363 hdd_ssr_restart_sap(hdd_ctx);
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301364
Sen, Devendra154b3c42017-02-13 20:44:15 +05301365 hdd_wlan_ssr_reinit_event();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301366 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001367}
1368
Jeff Johnson75b737d2017-08-29 14:24:41 -07001369int wlan_hdd_set_powersave(struct hdd_adapter *adapter,
Dustin Brownf660fb42016-09-09 12:04:00 -07001370 bool allow_power_save, uint32_t timeout)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001371{
Jeff Johnson2954ded2018-06-13 16:34:49 -07001372 mac_handle_t mac_handle;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001373 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001374
1375 if (NULL == adapter) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001376 hdd_err("Adapter NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001377 return -ENODEV;
1378 }
1379
1380 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1381 if (!hdd_ctx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001382 hdd_err("hdd context is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001383 return -EINVAL;
1384 }
1385
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001386 hdd_debug("Allow power save: %d", allow_power_save);
Jeff Johnson2954ded2018-06-13 16:34:49 -07001387 mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001388
Dustin Brown84411b02017-07-21 16:44:44 -07001389 /*
1390 * This is a workaround for defective AP's that send a disassoc
1391 * immediately after WPS connection completes. Defer powersave by a
1392 * small amount if the affected AP is detected.
1393 */
1394 if (allow_power_save &&
1395 adapter->device_mode == QDF_STA_MODE &&
Jeff Johnsonb9424862017-10-30 08:49:35 -07001396 !adapter->session.station.ap_supports_immediate_power_save) {
Dustin Brown84411b02017-07-21 16:44:44 -07001397 timeout = AUTO_PS_DEFER_TIMEOUT_MS;
1398 hdd_debug("Defer power-save due to AP spec non-conformance");
Krunal Soni364e0872017-05-10 21:24:34 -07001399 }
1400
Dustin Brownf660fb42016-09-09 12:04:00 -07001401 if (allow_power_save) {
1402 if (QDF_STA_MODE == adapter->device_mode ||
1403 QDF_P2P_CLIENT_MODE == adapter->device_mode) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001404 hdd_debug("Disabling Auto Power save timer");
Jeff Johnson2954ded2018-06-13 16:34:49 -07001405 sme_ps_disable_auto_ps_timer(mac_handle,
1406 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001407 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001408
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001409 if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001410 hdd_debug("Wlan driver Entering Power save");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411
1412 /*
1413 * Enter Power Save command received from GUI
1414 * this means DHCP is completed
1415 */
Yeshwanth Sriram Guntukaae03c432017-11-12 13:31:02 +05301416 if (timeout)
Jeff Johnson2954ded2018-06-13 16:34:49 -07001417 sme_ps_enable_auto_ps_timer(mac_handle,
Yeshwanth Sriram Guntukaae03c432017-11-12 13:31:02 +05301418 adapter->session_id,
1419 timeout);
1420 else
Jeff Johnson2954ded2018-06-13 16:34:49 -07001421 sme_ps_enable_disable(mac_handle,
1422 adapter->session_id,
Yeshwanth Sriram Guntukaae03c432017-11-12 13:31:02 +05301423 SME_PS_ENABLE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001424 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001425 hdd_debug("Power Save is not enabled in the cfg");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001426 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001427 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001428 hdd_debug("Wlan driver Entering Full Power");
Dustin Brownf660fb42016-09-09 12:04:00 -07001429
1430 /*
1431 * Enter Full power command received from GUI
1432 * this means we are disconnected
1433 */
Jeff Johnson2954ded2018-06-13 16:34:49 -07001434 sme_ps_disable_auto_ps_timer(mac_handle,
1435 adapter->session_id);
1436 sme_ps_enable_disable(mac_handle, adapter->session_id,
1437 SME_PS_DISABLE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001439
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001440 return 0;
1441}
1442
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001443static void wlan_hdd_print_suspend_fail_stats(struct hdd_context *hdd_ctx)
Dustin Brown105d7902016-10-03 16:27:59 -07001444{
Dustin Brownd9322482017-01-09 12:46:03 -08001445 struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301446
Dustin Brown105d7902016-10-03 16:27:59 -07001447 hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d",
Dustin Brownd9322482017-01-09 12:46:03 -08001448 stats->suspend_fail[SUSPEND_FAIL_IPA],
1449 stats->suspend_fail[SUSPEND_FAIL_RADAR],
1450 stats->suspend_fail[SUSPEND_FAIL_ROAM],
1451 stats->suspend_fail[SUSPEND_FAIL_SCAN],
1452 stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]);
Dustin Brown105d7902016-10-03 16:27:59 -07001453}
1454
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001455void wlan_hdd_inc_suspend_stats(struct hdd_context *hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001456 enum suspend_fail_reason reason)
1457{
1458 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001459 hdd_ctx->suspend_resume_stats.suspend_fail[reason]++;
Dustin Brown105d7902016-10-03 16:27:59 -07001460 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
1461}
1462
Dustin Brown5fbb1052017-08-11 17:25:51 -07001463#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
1464static inline void
1465hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
1466{
1467 cfg80211_sched_scan_results(wiphy);
1468}
1469#else
1470static inline void
1471hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
1472{
1473 cfg80211_sched_scan_results(wiphy, reqid);
1474}
1475#endif
1476
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001477/**
1478 * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1479 * @wiphy: Pointer to wiphy
1480 *
1481 * This API is called when cfg80211 driver resumes driver updates
1482 * latest sched_scan scan result(if any) to cfg80211 database
1483 *
1484 * Return: integer status
1485 */
1486static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1487{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001488 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301489 QDF_STATUS status = QDF_STATUS_SUCCESS;
Dustin Brownd9322482017-01-09 12:46:03 -08001490 int exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001491 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1492
Dustin Brown491d54b2018-03-14 12:39:11 -07001493 hdd_enter();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001494
Dustin Brownd9322482017-01-09 12:46:03 -08001495 if (cds_is_driver_recovering()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001496 hdd_debug("Driver is recovering; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001497 exit_code = 0;
1498 goto exit_with_code;
1499 }
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001500
Anurag Chouhan6d760662016-02-20 16:05:43 +05301501 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001502 hdd_err("Command not allowed in FTM mode");
Dustin Brownd9322482017-01-09 12:46:03 -08001503 exit_code = -EINVAL;
1504 goto exit_with_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001505 }
1506
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001507 exit_code = wlan_hdd_validate_context(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001508 if (exit_code) {
1509 hdd_err("Invalid HDD context");
1510 goto exit_with_code;
1511 }
Arun Khandavallifae92942016-08-01 13:31:08 +05301512
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001513 mutex_lock(&hdd_ctx->iface_change_lock);
1514 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1515 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001516 hdd_debug("Driver is not enabled; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001517 exit_code = 0;
1518 goto exit_with_code;
Arun Khandavallifae92942016-08-01 13:31:08 +05301519 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001520 mutex_unlock(&hdd_ctx->iface_change_lock);
Dustin Brownd9322482017-01-09 12:46:03 -08001521
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001522 pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_MEDIUM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001523
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301524 status = hdd_resume_wlan();
1525 if (status != QDF_STATUS_SUCCESS) {
1526 exit_code = 0;
1527 goto exit_with_code;
1528 }
Rajeev Kumareada0d02016-12-08 17:44:17 -08001529 /* Resume control path scheduler */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001530 if (hdd_ctx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001531 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001532 hdd_ctx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001533 }
1534#ifdef QCA_CONFIG_SMP
1535 /* Resume tlshim Rx thread */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001536 if (hdd_ctx->is_ol_rx_thread_suspended) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001537 complete(&cds_sched_context->ol_resume_rx_event);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001538 hdd_ctx->is_ol_rx_thread_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001539 }
1540#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001541
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301542 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301543 TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
Jeff Johnson214671b2017-10-30 19:45:23 -07001544 NO_SESSION, hdd_ctx->is_wiphy_suspended));
Jeff Johnson214671b2017-10-30 19:45:23 -07001545 hdd_ctx->is_wiphy_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001546
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001547 hdd_ctx->suspend_resume_stats.resumes++;
Dustin Brownd9322482017-01-09 12:46:03 -08001548 exit_code = 0;
1549
1550exit_with_code:
Dustin Browne74003f2018-03-14 12:51:58 -07001551 hdd_exit();
Dustin Brownd9322482017-01-09 12:46:03 -08001552 return exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001553}
1554
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001555int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1556{
1557 int ret;
1558
1559 cds_ssr_protect(__func__);
1560 ret = __wlan_hdd_cfg80211_resume_wlan(wiphy);
1561 cds_ssr_unprotect(__func__);
1562
1563 return ret;
1564}
1565
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001566static void hdd_suspend_cb(void)
1567{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001568 struct hdd_context *hdd_ctx;
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001569
1570 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1571 if (!hdd_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001572 hdd_err("HDD context is NULL");
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001573 return;
1574 }
1575
1576 complete(&hdd_ctx->mc_sus_event_var);
1577}
1578
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001579/**
1580 * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1581 * @wiphy: Pointer to wiphy
1582 * @wow: Pointer to wow
1583 *
1584 * This API is called when cfg80211 driver suspends
1585 *
1586 * Return: integer status
1587 */
1588static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1589 struct cfg80211_wowlan *wow)
1590{
1591#ifdef QCA_CONFIG_SMP
1592#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */
1593#endif
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001594 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001595 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001596 struct hdd_adapter *adapter;
Jeff Johnson5287de52017-10-28 12:23:06 -07001597 struct hdd_scan_info *scan_info;
Jeff Johnson2954ded2018-06-13 16:34:49 -07001598 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001599 int rc;
1600
Dustin Brown491d54b2018-03-14 12:39:11 -07001601 hdd_enter();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001602
Anurag Chouhan6d760662016-02-20 16:05:43 +05301603 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001604 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001605 return -EINVAL;
1606 }
1607
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001608 rc = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301609 if (0 != rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001610 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001611
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001612 mutex_lock(&hdd_ctx->iface_change_lock);
1613 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1614 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001615 hdd_debug("Driver Modules not Enabled ");
Arun Khandavallifae92942016-08-01 13:31:08 +05301616 return 0;
1617 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001618 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavallifae92942016-08-01 13:31:08 +05301619
Jeff Johnson2954ded2018-06-13 16:34:49 -07001620 mac_handle = hdd_ctx->mac_handle;
1621
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001622 /* If RADAR detection is in progress (HDD), prevent suspend. The flag
1623 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true
1624 * until CAC is done for a SoftAP which is in started state.
1625 */
Dustin Brown920397d2017-12-13 16:27:50 -08001626 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson1b780e42017-10-31 14:11:45 -07001627 if (wlan_hdd_validate_session_id(adapter->session_id)) {
Rajeev Kumar9176ca42018-05-03 09:20:40 -07001628 hdd_debug("invalid session id: %d", adapter->session_id);
Dustin Brown920397d2017-12-13 16:27:50 -08001629 continue;
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301630 }
1631
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001632 if (QDF_SAP_MODE == adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001633 if (BSS_START ==
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07001634 WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter)->bss_state &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001635 true ==
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001636 WLAN_HDD_GET_AP_CTX_PTR(adapter)->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001637 dfs_cac_block_tx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001638 hdd_err("RADAR detection in progress, do not allow suspend");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001639 wlan_hdd_inc_suspend_stats(hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001640 SUSPEND_FAIL_RADAR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641 return -EAGAIN;
Jeff Johnson60cbd2d2017-11-03 18:26:28 -07001642 } else if (!hdd_ctx->config->enable_sap_suspend) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001643 /* return -EOPNOTSUPP if SAP does not support
1644 * suspend
1645 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001646 hdd_err("SAP does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647 return -EOPNOTSUPP;
1648 }
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001649 } else if (QDF_P2P_GO_MODE == adapter->device_mode) {
Jeff Johnson60cbd2d2017-11-03 18:26:28 -07001650 if (!hdd_ctx->config->enable_sap_suspend) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001651 /* return -EOPNOTSUPP if GO does not support
1652 * suspend
1653 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001654 hdd_err("GO does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001655 return -EOPNOTSUPP;
1656 }
1657 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001658 }
1659
1660 /* Stop ongoing scan on each interface */
Dustin Brown920397d2017-12-13 16:27:50 -08001661 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson5287de52017-10-28 12:23:06 -07001662 scan_info = &adapter->scan_info;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001663
Jeff Johnson2954ded2018-06-13 16:34:49 -07001664 if (sme_neighbor_middle_of_roaming(mac_handle,
Padma, Santhosh Kumar41552782018-06-29 15:31:25 +05301665 adapter->session_id) ||
1666 hdd_is_roaming_in_progress(hdd_ctx)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001667 hdd_err("Roaming in progress, do not allow suspend");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001668 wlan_hdd_inc_suspend_stats(hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001669 SUSPEND_FAIL_ROAM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670 return -EAGAIN;
1671 }
1672
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001673 wlan_abort_scan(hdd_ctx->hdd_pdev, INVAL_PDEV_ID,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001674 adapter->session_id, INVALID_SCAN_ID, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001675 }
1676
Dustin Brown84411b02017-07-21 16:44:44 -07001677 /* flush any pending powersave timers */
Dustin Brown920397d2017-12-13 16:27:50 -08001678 hdd_for_each_adapter(hdd_ctx, adapter)
Jeff Johnson2954ded2018-06-13 16:34:49 -07001679 sme_ps_timer_flush_sync(mac_handle, adapter->session_id);
Dustin Brown84411b02017-07-21 16:44:44 -07001680
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001681 /*
1682 * Suspend IPA early before proceeding to suspend other entities like
1683 * firmware to avoid any race conditions.
1684 */
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301685 if (ucfg_ipa_suspend(hdd_ctx->hdd_pdev)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001686 hdd_err("IPA not ready to suspend!");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001687 wlan_hdd_inc_suspend_stats(hdd_ctx, SUSPEND_FAIL_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688 return -EAGAIN;
1689 }
1690
Rajeev Kumareada0d02016-12-08 17:44:17 -08001691 /* Suspend control path scheduler */
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001692 scheduler_register_hdd_suspend_callback(hdd_suspend_cb);
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301693 scheduler_set_event_mask(MC_SUSPEND_EVENT);
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001694 scheduler_wake_up_controller_thread();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695
Rajeev Kumareada0d02016-12-08 17:44:17 -08001696 /* Wait for suspend confirmation from scheduler */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001697 rc = wait_for_completion_timeout(&hdd_ctx->mc_sus_event_var,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001698 msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
1699 if (!rc) {
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301700 scheduler_clear_event_mask(MC_SUSPEND_EVENT);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001701 hdd_err("Failed to stop mc thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702 goto resume_tx;
1703 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001704 hdd_ctx->is_scheduler_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001705
1706#ifdef QCA_CONFIG_SMP
1707 /* Suspend tlshim rx thread */
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301708 set_bit(RX_SUSPEND_EVENT, &cds_sched_context->ol_rx_event_flag);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001709 wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue);
1710 rc = wait_for_completion_timeout(&cds_sched_context->
1711 ol_suspend_rx_event,
1712 msecs_to_jiffies
1713 (RX_TLSHIM_SUSPEND_TIMEOUT));
1714 if (!rc) {
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301715 clear_bit(RX_SUSPEND_EVENT,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716 &cds_sched_context->ol_rx_event_flag);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001717 hdd_err("Failed to stop tl_shim rx thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718 goto resume_all;
1719 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001720 hdd_ctx->is_ol_rx_thread_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721#endif
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301722 if (hdd_suspend_wlan() < 0)
1723 goto resume_all;
1724
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301725 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301726 TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
Jeff Johnson214671b2017-10-30 19:45:23 -07001727 NO_SESSION, hdd_ctx->is_wiphy_suspended));
1728 hdd_ctx->is_wiphy_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001729
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001730 pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_NONE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001731
Dustin Browne74003f2018-03-14 12:51:58 -07001732 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001733 return 0;
1734
1735#ifdef QCA_CONFIG_SMP
1736resume_all:
1737
Rajeev Kumar0b732952016-12-08 17:51:39 -08001738 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001739 hdd_ctx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740#endif
1741
1742resume_tx:
1743
1744 hdd_resume_wlan();
1745 return -ETIME;
1746
1747}
1748
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1750 struct cfg80211_wowlan *wow)
1751{
1752 int ret;
1753
1754 cds_ssr_protect(__func__);
1755 ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
1756 cds_ssr_unprotect(__func__);
1757
1758 return ret;
1759}
1760
1761/**
Komal Seelama89be8d2016-09-29 11:09:26 +05301762 * hdd_stop_dhcp_ind() - API to stop DHCP sequence
1763 * @adapter: Adapter on which DHCP needs to be stopped
1764 *
1765 * Release the wakelock held for DHCP process and allow
1766 * the runtime pm to continue
1767 *
1768 * Return: None
1769 */
Jeff Johnson75b737d2017-08-29 14:24:41 -07001770static void hdd_stop_dhcp_ind(struct hdd_adapter *adapter)
Komal Seelama89be8d2016-09-29 11:09:26 +05301771{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001772 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Komal Seelama89be8d2016-09-29 11:09:26 +05301773
Srinivas Girigowdac06543c2017-03-09 15:10:03 -08001774 hdd_debug("DHCP stop indicated through power save");
Jeff Johnson2954ded2018-06-13 16:34:49 -07001775 sme_dhcp_stop_ind(hdd_ctx->mac_handle, adapter->device_mode,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001776 adapter->mac_addr.bytes,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001777 adapter->session_id);
Komal Seelama89be8d2016-09-29 11:09:26 +05301778 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
Jingxiang Geb49aa302018-01-17 20:54:15 +08001779 qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect);
Komal Seelama89be8d2016-09-29 11:09:26 +05301780}
1781
1782/**
1783 * hdd_start_dhcp_ind() - API to start DHCP sequence
1784 * @adapter: Adapter on which DHCP needs to be stopped
1785 *
1786 * Prevent APPS suspend and the runtime suspend during
1787 * DHCP sequence
1788 *
1789 * Return: None
1790 */
Jeff Johnson75b737d2017-08-29 14:24:41 -07001791static void hdd_start_dhcp_ind(struct hdd_adapter *adapter)
Komal Seelama89be8d2016-09-29 11:09:26 +05301792{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001793 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Komal Seelama89be8d2016-09-29 11:09:26 +05301794
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001795 hdd_debug("DHCP start indicated through power save");
Jingxiang Geb49aa302018-01-17 20:54:15 +08001796 qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.connect);
Dustin Brownceed67e2017-05-26 11:57:31 -07001797 hdd_prevent_suspend_timeout(HDD_WAKELOCK_TIMEOUT_CONNECT,
1798 WIFI_POWER_EVENT_WAKELOCK_DHCP);
Jeff Johnson2954ded2018-06-13 16:34:49 -07001799 sme_dhcp_start_ind(hdd_ctx->mac_handle, adapter->device_mode,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001800 adapter->mac_addr.bytes,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001801 adapter->session_id);
Komal Seelama89be8d2016-09-29 11:09:26 +05301802}
1803
1804/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001805 * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
1806 * @wiphy: Pointer to wiphy
1807 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07001808 * @allow_power_save: is wlan allowed to go into power save mode
1809 * @timeout: Timeout value in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001810 *
1811 * Return: 0 for success, non-zero for failure
1812 */
1813static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07001814 struct net_device *dev,
1815 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001816 int timeout)
1817{
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001818 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001819 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001820 int status;
1821
Dustin Brown491d54b2018-03-14 12:39:11 -07001822 hdd_enter();
Dustin Brownecfce632016-09-13 10:41:45 -07001823
Dustin Brownf660fb42016-09-09 12:04:00 -07001824 if (timeout < 0) {
Yeshwanth Sriram Guntukaae03c432017-11-12 13:31:02 +05301825 hdd_debug("User space timeout: %d; Enter full power or power save",
1826 timeout);
1827 timeout = 0;
Dustin Brownf660fb42016-09-09 12:04:00 -07001828 }
1829
Anurag Chouhan6d760662016-02-20 16:05:43 +05301830 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001831 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001832 return -EINVAL;
1833 }
1834
Jeff Johnson1b780e42017-10-31 14:11:45 -07001835 if (wlan_hdd_validate_session_id(adapter->session_id)) {
1836 hdd_err("invalid session id: %d", adapter->session_id);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301837 return -EINVAL;
1838 }
1839
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301840 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001841 TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001842 adapter->session_id, timeout));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001843
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001844 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001845 status = wlan_hdd_validate_context(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001846
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301847 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001848 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001849
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001850 mutex_lock(&hdd_ctx->iface_change_lock);
1851 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1852 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001853 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05301854 return 0;
1855 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001856 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavalli99286452016-08-22 12:13:41 +05301857
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001858 status = wlan_hdd_set_powersave(adapter, allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001859
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001860 allow_power_save ? hdd_stop_dhcp_ind(adapter) :
1861 hdd_start_dhcp_ind(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862
Dustin Browne74003f2018-03-14 12:51:58 -07001863 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001864 return status;
1865}
1866
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001867int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07001868 struct net_device *dev,
1869 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001870 int timeout)
1871{
1872 int ret;
1873
1874 cds_ssr_protect(__func__);
Dustin Brownf660fb42016-09-09 12:04:00 -07001875 ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev,
1876 allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877 cds_ssr_unprotect(__func__);
1878
1879 return ret;
1880}
1881
1882/**
1883 * __wlan_hdd_cfg80211_set_txpower() - set TX power
1884 * @wiphy: Pointer to wiphy
1885 * @wdev: Pointer to network device
1886 * @type: TX power setting type
1887 * @dbm: TX power in dbm
1888 *
1889 * Return: 0 for success, non-zero for failure
1890 */
1891static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001892 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001893 enum nl80211_tx_power_setting type,
1894 int dbm)
1895{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001896 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Jeff Johnson2954ded2018-06-13 16:34:49 -07001897 mac_handle_t mac_handle;
Dustin Brownce5b3d32018-01-17 15:07:38 -08001898 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
1899 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BCAST_INIT;
Jeff Johnson2954ded2018-06-13 16:34:49 -07001900 QDF_STATUS status;
1901 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001902
Dustin Brown491d54b2018-03-14 12:39:11 -07001903 hdd_enter();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001904
Anurag Chouhan6d760662016-02-20 16:05:43 +05301905 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001906 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001907 return -EINVAL;
1908 }
1909
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301910 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911 TRACE_CODE_HDD_CFG80211_SET_TXPOWER,
1912 NO_SESSION, type));
1913
Jeff Johnson2954ded2018-06-13 16:34:49 -07001914 errno = wlan_hdd_validate_context(hdd_ctx);
1915 if (errno)
1916 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001917
Jeff Johnson2954ded2018-06-13 16:34:49 -07001918 mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001919
Jeff Johnson2954ded2018-06-13 16:34:49 -07001920 status = sme_cfg_set_int(mac_handle, WNI_CFG_CURRENT_TX_POWER_LEVEL,
1921 dbm);
1922 if (QDF_IS_STATUS_ERROR(status)) {
1923 hdd_err("sme_cfg_set_int failed for tx power %hu, %d",
1924 dbm, status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001925 return -EIO;
1926 }
1927
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001928 hdd_debug("Set tx power level %d dbm", dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001929
1930 switch (type) {
1931 /* Automatically determine transmit power */
1932 case NL80211_TX_POWER_AUTOMATIC:
1933 /* Fall through */
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301934 case NL80211_TX_POWER_LIMITED:
1935 /* Limit TX power by the mBm parameter */
Jeff Johnson2954ded2018-06-13 16:34:49 -07001936 status = sme_set_max_tx_power(mac_handle, bssid, selfMac, dbm);
1937 if (QDF_IS_STATUS_ERROR(status)) {
1938 hdd_err("Setting maximum tx power failed, %d", status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001939 return -EIO;
1940 }
1941 break;
1942
1943 case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001944 hdd_err("NL80211_TX_POWER_FIXED not supported");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001945 return -EOPNOTSUPP;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946
1947 default:
Jeff Johnsonc3273322016-07-06 15:28:17 -07001948 hdd_err("Invalid power setting type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001949 return -EIO;
1950 }
1951
Dustin Browne74003f2018-03-14 12:51:58 -07001952 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001953 return 0;
1954}
1955
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001956int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001957 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001958 enum nl80211_tx_power_setting type,
1959 int dbm)
1960{
1961 int ret;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301962
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001963 cds_ssr_protect(__func__);
1964 ret = __wlan_hdd_cfg80211_set_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001966 type, dbm);
1967 cds_ssr_unprotect(__func__);
1968
1969 return ret;
1970}
1971
Naveen Rawate8b1b822018-01-30 09:46:16 -08001972#ifdef QCA_SUPPORT_CP_STATS
1973static void wlan_hdd_get_tx_power(struct hdd_adapter *adapter, int *dbm)
1974{
1975 wlan_cfg80211_mc_cp_stats_get_tx_power(adapter->hdd_vdev, dbm);
1976}
1977#else
1978static void wlan_hdd_get_tx_power(struct hdd_adapter *adapter, int *dbm)
1979{
1980 wlan_hdd_get_class_astats(adapter);
1981 *dbm = adapter->hdd_stats.class_a_stat.max_pwr;
1982}
1983#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001984/**
1985 * __wlan_hdd_cfg80211_get_txpower() - get TX power
1986 * @wiphy: Pointer to wiphy
1987 * @wdev: Pointer to network device
1988 * @dbm: Pointer to TX power in dbm
1989 *
1990 * Return: 0 for success, non-zero for failure
1991 */
1992static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001993 struct wireless_dev *wdev,
Srinivas Girigowda5557a392017-03-09 14:28:36 -08001994 int *dbm)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001995{
1996
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001997 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08001998 struct net_device *ndev = wdev->netdev;
Jeff Johnson75b737d2017-08-29 14:24:41 -07001999 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002000 int status;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07002001 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002002
Dustin Brown491d54b2018-03-14 12:39:11 -07002003 hdd_enter();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002004
Anurag Chouhan6d760662016-02-20 16:05:43 +05302005 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002006 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002007 return -EINVAL;
2008 }
2009
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002010 status = wlan_hdd_validate_context(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011 if (0 != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002012 *dbm = 0;
2013 return status;
2014 }
2015
Arun Khandavalli99286452016-08-22 12:13:41 +05302016 /* Validate adapter sessionId */
Jeff Johnson1b780e42017-10-31 14:11:45 -07002017 if (wlan_hdd_validate_session_id(adapter->session_id)) {
2018 hdd_err("invalid session id: %d", adapter->session_id);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002019 return -EINVAL;
Arun Khandavalli99286452016-08-22 12:13:41 +05302020 }
2021
Abhinav Kumar50d4dc72018-06-15 16:35:50 +05302022 if (sta_ctx->hdd_reassoc_scenario) {
2023 hdd_debug("Roaming is in progress, rej this req");
2024 return -EINVAL;
2025 }
2026
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002027 mutex_lock(&hdd_ctx->iface_change_lock);
2028 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2029 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002030 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05302031 /* Send cached data to upperlayer*/
Jeff Johnson861dd4f2017-10-24 10:10:40 -07002032 *dbm = adapter->hdd_stats.class_a_stat.max_pwr;
Arun Khandavalli99286452016-08-22 12:13:41 +05302033 return 0;
2034 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002035 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavalli99286452016-08-22 12:13:41 +05302036
Ganesh Kondabattinif847f062017-05-26 12:36:24 +05302037 if (sta_ctx->conn_info.connState != eConnectionState_Associated) {
2038 hdd_debug("Not associated");
2039 /*To keep GUI happy */
2040 *dbm = 0;
2041 return 0;
2042 }
2043
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302044 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302045 TRACE_CODE_HDD_CFG80211_GET_TXPOWER,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002046 adapter->session_id, adapter->device_mode));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002047
Naveen Rawate8b1b822018-01-30 09:46:16 -08002048 wlan_hdd_get_tx_power(adapter, dbm);
2049 hdd_debug("power: %d", *dbm);
2050
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051 return 0;
2052}
2053
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002054int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002056 int *dbm)
2057{
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002058 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002059
2060 cds_ssr_protect(__func__);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002061 ret = __wlan_hdd_cfg80211_get_txpower(wiphy, wdev, dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002062 cds_ssr_unprotect(__func__);
2063
2064 return ret;
2065}
Kapil Gupta6213c012016-09-02 19:39:09 +05302066
Jeff Johnson4fbee2f2017-10-03 11:19:35 -07002067int hdd_set_qpower_config(struct hdd_context *hddctx,
2068 struct hdd_adapter *adapter,
Dustin Brown10a7b712016-10-07 10:31:16 -07002069 u8 qpower)
Kapil Gupta6213c012016-09-02 19:39:09 +05302070{
Dustin Brown10a7b712016-10-07 10:31:16 -07002071 QDF_STATUS status;
Kapil Gupta6213c012016-09-02 19:39:09 +05302072
2073 if (!hddctx->config->enablePowersaveOffload) {
2074 hdd_err("qpower is disabled in configuration");
2075 return -EINVAL;
2076 }
Manjeet Singh91b7bb82017-02-10 18:35:40 +05302077 if (adapter->device_mode != QDF_STA_MODE &&
2078 adapter->device_mode != QDF_P2P_CLIENT_MODE) {
Dustin Brownbacc48f2018-03-14 14:48:44 -07002079 hdd_info("QPOWER only allowed in STA/P2P-Client modes:%d",
2080 adapter->device_mode);
Manjeet Singh91b7bb82017-02-10 18:35:40 +05302081 return -EINVAL;
2082 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002083
Kapil Gupta6213c012016-09-02 19:39:09 +05302084 if (qpower > PS_DUTY_CYCLING_QPOWER ||
2085 qpower < PS_LEGACY_NODEEPSLEEP) {
Dustin Brown10a7b712016-10-07 10:31:16 -07002086 hdd_err("invalid qpower value: %d", qpower);
Kapil Gupta6213c012016-09-02 19:39:09 +05302087 return -EINVAL;
2088 }
Kapil Gupta6213c012016-09-02 19:39:09 +05302089
Kiran Kumar Lokere7006e0a2017-03-07 19:28:36 -08002090 if (hddctx->config->nMaxPsPoll) {
2091 if ((qpower == PS_QPOWER_NODEEPSLEEP) ||
2092 (qpower == PS_LEGACY_NODEEPSLEEP))
2093 qpower = PS_LEGACY_NODEEPSLEEP;
2094 else
2095 qpower = PS_LEGACY_DEEPSLEEP;
2096 hdd_info("Qpower disabled, %d", qpower);
2097 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07002098 status = wma_set_qpower_config(adapter->session_id, qpower);
Dustin Brown10a7b712016-10-07 10:31:16 -07002099 if (status != QDF_STATUS_SUCCESS) {
2100 hdd_err("failed to configure qpower: %d", status);
2101 return -EINVAL;
Kapil Gupta6213c012016-09-02 19:39:09 +05302102 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002103
Kapil Gupta6213c012016-09-02 19:39:09 +05302104 return 0;
2105}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002106
Dustin Brown54096432017-02-23 13:00:44 -08002107
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002108#ifdef WLAN_SUSPEND_RESUME_TEST
Dustin Brownbc81a472016-10-26 16:56:59 -07002109static struct net_device *g_dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002110static struct wiphy *g_wiphy;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002111static enum wow_resume_trigger g_resume_trigger;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002112
2113#define HDD_FA_SUSPENDED_BIT (0)
2114static unsigned long fake_apps_state;
2115
Dustin Brownd53d1a82016-10-03 12:57:33 -07002116/**
2117 * __hdd_wlan_fake_apps_resume() - The core logic for
2118 * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(),
2119 * which is only need for non-irq resume
Dustin Brownbc81a472016-10-26 16:56:59 -07002120 * @wiphy: the kernel wiphy struct for the device being resumed
2121 * @dev: the kernel net_device struct for the device being resumed
Dustin Brownd53d1a82016-10-03 12:57:33 -07002122 *
Dustin Brownbc81a472016-10-26 16:56:59 -07002123 * Return: none, calls QDF_BUG() on failure
Dustin Brownd53d1a82016-10-03 12:57:33 -07002124 */
Dustin Brownbc81a472016-10-26 16:56:59 -07002125static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy,
2126 struct net_device *dev)
Dustin Brownd53d1a82016-10-03 12:57:33 -07002127{
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002128 struct hif_opaque_softc *hif_ctx;
Dustin Brownddb59702017-01-12 16:20:31 -08002129 qdf_device_t qdf_dev;
Dustin Brownd53d1a82016-10-03 12:57:33 -07002130
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002131 hdd_info("Unit-test resume WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002132
2133 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2134 if (!qdf_dev) {
2135 hdd_err("Failed to get QDF device context");
2136 QDF_BUG(0);
2137 return;
2138 }
2139
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002140 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2141 if (!hif_ctx) {
2142 hdd_err("Failed to get HIF context");
2143 return;
2144 }
2145
Dustin Brownd53d1a82016-10-03 12:57:33 -07002146 if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002147 hdd_alert("Not unit-test suspended; Nothing to do");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002148 return;
2149 }
2150
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002151 /* simulate kernel disable irqs */
2152 QDF_BUG(!hif_apps_wake_irq_disable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002153
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002154 QDF_BUG(!wlan_hdd_bus_resume_noirq());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002155
2156 /* simulate kernel enable irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002157 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002158
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002159 QDF_BUG(!wlan_hdd_bus_resume());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002160
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002161 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
2162
2163 if (g_resume_trigger == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2164 hif_vote_link_down(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002165
2166 dev->watchdog_timeo = HDD_TX_TIMEOUT;
Dustin Brown562b9672016-12-22 15:25:33 -08002167
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002168 hdd_alert("Unit-test resume succeeded");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002169}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002170
2171/**
2172 * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming
2173 * from unit-test initiated suspend from irq wakeup signal
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002174 *
2175 * Resume wlan after getting very 1st CE interrupt from target
2176 *
2177 * Return: none
2178 */
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002179static void hdd_wlan_fake_apps_resume_irq_callback(void)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002180{
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002181 hdd_info("Trigger unit-test resume WLAN");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002182
2183 QDF_BUG(g_wiphy);
Dustin Brownbc81a472016-10-26 16:56:59 -07002184 QDF_BUG(g_dev);
2185 __hdd_wlan_fake_apps_resume(g_wiphy, g_dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002186 g_wiphy = NULL;
Dustin Brownbc81a472016-10-26 16:56:59 -07002187 g_dev = NULL;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002188}
2189
Dustin Brown54096432017-02-23 13:00:44 -08002190int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev,
2191 enum wow_interface_pause pause_setting,
2192 enum wow_resume_trigger resume_setting)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002193{
Rajeev Kumar15b40a22018-04-12 11:45:24 -07002194 int errno;
Dustin Brownddb59702017-01-12 16:20:31 -08002195 qdf_device_t qdf_dev;
2196 struct hif_opaque_softc *hif_ctx;
Rajeev Kumar15b40a22018-04-12 11:45:24 -07002197 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Dustin Brown54096432017-02-23 13:00:44 -08002198 struct wow_enable_params wow_params = {
2199 .is_unit_test = true,
2200 .interface_pause = pause_setting,
2201 .resume_trigger = resume_setting
2202 };
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002203
Rajeev Kumar15b40a22018-04-12 11:45:24 -07002204 if (wlan_hdd_validate_context(hdd_ctx))
2205 return -EINVAL;
2206
2207 if (!hdd_ctx->config->is_unit_test_framework_enabled) {
2208 hdd_warn_rl("UT framework is disabled");
2209 return -EINVAL;
2210 }
2211
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002212 hdd_info("Unit-test suspend WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002213
Dustin Brown54096432017-02-23 13:00:44 -08002214 if (pause_setting < WOW_INTERFACE_PAUSE_DEFAULT ||
2215 pause_setting >= WOW_INTERFACE_PAUSE_COUNT) {
2216 hdd_err("Invalid interface pause %d (expected range [0, 2])",
2217 pause_setting);
2218 return -EINVAL;
2219 }
2220
2221 if (resume_setting < WOW_RESUME_TRIGGER_DEFAULT ||
2222 resume_setting >= WOW_RESUME_TRIGGER_COUNT) {
2223 hdd_err("Invalid resume trigger %d (expected range [0, 2])",
2224 resume_setting);
2225 return -EINVAL;
2226 }
2227
Dustin Brownddb59702017-01-12 16:20:31 -08002228 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2229 if (!qdf_dev) {
2230 hdd_err("Failed to get QDF device context");
2231 return -EINVAL;
2232 }
2233
2234 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2235 if (!hif_ctx) {
2236 hdd_err("Failed to get HIF context");
2237 return -EINVAL;
2238 }
2239
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002240 if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002241 hdd_alert("Already unit-test suspended; Nothing to do");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002242 return 0;
2243 }
2244
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002245 /* pci link is needed to wakeup from HTC wakeup trigger */
2246 if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2247 hif_vote_link_up(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002248
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002249 errno = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL);
2250 if (errno)
2251 goto link_down;
2252
2253 errno = wlan_hdd_unit_test_bus_suspend(wow_params);
2254 if (errno)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002255 goto cfg80211_resume;
2256
2257 /* simulate kernel disabling irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002258 errno = hif_apps_irqs_disable(hif_ctx);
2259 if (errno)
2260 goto bus_resume;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002261
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002262 errno = wlan_hdd_bus_suspend_noirq();
2263 if (errno)
2264 goto enable_irqs;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002265
Dustin Brownbc81a472016-10-26 16:56:59 -07002266 /* pass wiphy/dev to callback via global variables */
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002267 g_wiphy = wiphy;
Dustin Brownbc81a472016-10-26 16:56:59 -07002268 g_dev = dev;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002269 g_resume_trigger = resume_setting;
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002270 hif_ut_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002271
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002272 /* re-enable wake irq */
2273 errno = hif_apps_wake_irq_enable(hif_ctx);
2274 if (errno)
2275 goto fake_apps_resume;
2276
Dustin Brownbc81a472016-10-26 16:56:59 -07002277 /*
2278 * Tell the kernel not to worry if TX queues aren't moving. This is
2279 * expected since we are suspending the wifi hardware, but not APPS
2280 */
2281 dev->watchdog_timeo = INT_MAX;
2282
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002283 hdd_alert("Unit-test suspend succeeded");
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002284
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002285 return 0;
2286
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002287fake_apps_resume:
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002288 hif_ut_apps_resume(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002289
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002290enable_irqs:
2291 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
2292
2293bus_resume:
2294 QDF_BUG(!wlan_hdd_bus_resume());
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002295
2296cfg80211_resume:
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002297 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002298
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002299link_down:
2300 hif_vote_link_down(hif_ctx);
2301
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002302 clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state);
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002303 hdd_err("Unit-test suspend failed: %d", errno);
2304
2305 return errno;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002306}
2307
Dustin Brownbc81a472016-10-26 16:56:59 -07002308int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002309{
Dustin Brownddb59702017-01-12 16:20:31 -08002310 struct hif_opaque_softc *hif_ctx;
Rajeev Kumar15b40a22018-04-12 11:45:24 -07002311 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
2312
2313 if (wlan_hdd_validate_context(hdd_ctx))
2314 return -EINVAL;
2315
2316 if (!hdd_ctx->config->is_unit_test_framework_enabled) {
2317 hdd_warn_rl("UT framework is disabled");
2318 return -EINVAL;
2319 }
Dustin Brownddb59702017-01-12 16:20:31 -08002320
2321 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2322 if (!hif_ctx) {
2323 hdd_err("Failed to get HIF context");
2324 return -EINVAL;
2325 }
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002326
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002327 hif_ut_apps_resume(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002328 __hdd_wlan_fake_apps_resume(wiphy, dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002329
2330 return 0;
2331}
2332#endif