blob: 4966207ded32bd71a65f8b92290c76dd6c91699d [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"
Mohit Khanna70322002018-05-15 19:21:32 -070077#include <dp_txrx.h>
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +053078#include "wlan_ipa_ucfg_api.h"
Naveen Rawate8b1b822018-01-30 09:46:16 -080079#include <wlan_cfg80211_mc_cp_stats.h>
Wu Gao4a1ec8c2018-07-23 19:18:40 +080080#include "wlan_p2p_ucfg_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080081/* Preprocessor definitions and constants */
Yue Ma5fe30dd2017-05-02 15:47:40 -070082#ifdef QCA_WIFI_NAPIER_EMULATION
83#define HDD_SSR_BRING_UP_TIME 3000000
84#else
Yue Ma4ea4f052015-10-27 12:25:27 -070085#define HDD_SSR_BRING_UP_TIME 30000
Yue Ma5fe30dd2017-05-02 15:47:40 -070086#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080087
Mohit Khanna70322002018-05-15 19:21:32 -070088/* timeout in msec to wait for RX_THREAD to suspend */
89#define HDD_RXTHREAD_SUSPEND_TIMEOUT 200
90
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080091/* Type declarations */
92
Abhishek Singhbaea27d2016-04-27 13:29:30 +053093#ifdef FEATURE_WLAN_DIAG_SUPPORT
Abhishek Singhbaea27d2016-04-27 13:29:30 +053094void hdd_wlan_suspend_resume_event(uint8_t state)
95{
96 WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend);
97 qdf_mem_zero(&suspend_state, sizeof(suspend_state));
98
99 suspend_state.state = state;
100 WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
101}
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530102
103/**
104 * hdd_wlan_offload_event()- send offloads event
105 * @type: offload type
106 * @state: enabled or disabled
107 *
108 * This Function send offloads enable/disable diag event
109 *
110 * Return: void.
111 */
112
113void hdd_wlan_offload_event(uint8_t type, uint8_t state)
114{
115 WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req);
116 qdf_mem_zero(&host_offload, sizeof(host_offload));
117
118 host_offload.offload_type = type;
119 host_offload.state = state;
120
121 WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ);
122}
Abhishek Singhbaea27d2016-04-27 13:29:30 +0530123#endif
124
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800125/**
Mukul Sharma3d36c392017-01-18 18:39:12 +0530126 * hdd_enable_gtk_offload() - enable GTK offload
127 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800128 *
Mukul Sharma3d36c392017-01-18 18:39:12 +0530129 * Central function to enable GTK offload.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800130 *
131 * Return: nothing
132 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700133static void hdd_enable_gtk_offload(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800134{
Mukul Sharma3d36c392017-01-18 18:39:12 +0530135 QDF_STATUS status;
Jeff Johnson4f7f7c62017-10-05 08:53:41 -0700136
Mukul Sharma3d36c392017-01-18 18:39:12 +0530137 status = pmo_ucfg_enable_gtk_offload_in_fwr(adapter->hdd_vdev);
138 if (status != QDF_STATUS_SUCCESS)
139 hdd_info("Failed to enable gtk offload");
140}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800141
Mukul Sharma3d36c392017-01-18 18:39:12 +0530142/**
143 * hdd_disable_gtk_offload() - disable GTK offload
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700144 * @adapter: pointer to the adapter
Mukul Sharma3d36c392017-01-18 18:39:12 +0530145 *
146 * Central function to disable GTK offload.
147 *
148 * Return: nothing
149 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700150static void hdd_disable_gtk_offload(struct hdd_adapter *adapter)
Mukul Sharma3d36c392017-01-18 18:39:12 +0530151{
152 struct pmo_gtk_rsp_req gtk_rsp_request;
153 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800154
Mukul Sharma3d36c392017-01-18 18:39:12 +0530155 /* ensure to get gtk rsp first before disable it*/
156 gtk_rsp_request.callback =
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530157 wlan_hdd_cfg80211_update_replay_counter_cb;
Mukul Sharma3d36c392017-01-18 18:39:12 +0530158 /* Passing as void* as PMO does not know legacy HDD adapter type */
159 gtk_rsp_request.callback_context =
160 (void *)adapter;
161 status = pmo_ucfg_get_gtk_rsp(adapter->hdd_vdev,
162 &gtk_rsp_request);
163 if (status != QDF_STATUS_SUCCESS) {
164 hdd_err("Failed to send get gtk rsp status:%d", status);
165 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800166 }
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800167 hdd_debug("send get_gtk_rsp successful");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530168 status = pmo_ucfg_disable_gtk_offload_in_fwr(adapter->hdd_vdev);
169 if (status != QDF_STATUS_SUCCESS)
170 hdd_info("Failed to disable gtk offload");
171
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800172}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800173
Qiwei Cai1083f5b2018-07-02 19:10:11 +0800174#ifdef WLAN_NS_OFFLOAD
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800175/**
176 * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function
177 * @nb: notifier block that was registered with the kernel
178 * @data: (unused) generic data that was registered with the kernel
179 * @arg: (unused) generic argument that was registered with the kernel
180 *
181 * This is a callback function that is registered with the kernel via
182 * register_inet6addr_notifier() which allows the driver to be
183 * notified when there is an IPv6 address change.
184 *
185 * Return: NOTIFY_DONE to indicate we don't care what happens with
186 * other callbacks
187 */
188static int __wlan_hdd_ipv6_changed(struct notifier_block *nb,
Dustin Brownf13b8c32017-05-19 17:23:08 -0700189 unsigned long data, void *arg)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800190{
191 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
192 struct net_device *ndev = ifa->idev->dev;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700193 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700194 struct hdd_context *hdd_ctx;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700195 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800196
Dustin Brownfdf17c12018-03-14 12:55:34 -0700197 hdd_enter_dev(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530198
Dustin Brownf13b8c32017-05-19 17:23:08 -0700199 errno = hdd_validate_adapter(adapter);
200 if (errno)
201 goto exit;
202
203 if (adapter->dev == ndev &&
204 (adapter->device_mode == QDF_STA_MODE ||
205 adapter->device_mode == QDF_P2P_CLIENT_MODE ||
206 adapter->device_mode == QDF_NDI_MODE)) {
207 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
208 errno = wlan_hdd_validate_context(hdd_ctx);
209 if (errno)
210 goto exit;
211
Nachiket Kukadec9045fe2017-06-19 15:14:43 +0530212 /* Ignore if the interface is down */
213 if (!(ndev->flags & IFF_UP)) {
214 hdd_err("Rcvd change addr request on %s(flags 0x%X)",
215 ndev->name, ndev->flags);
216 hdd_err("NETDEV Interface is down, ignoring...");
217 goto exit;
218 }
219
Dustin Brownf13b8c32017-05-19 17:23:08 -0700220 hdd_debug("invoking sme_dhcp_done_ind");
Jeff Johnson2954ded2018-06-13 16:34:49 -0700221 sme_dhcp_done_ind(hdd_ctx->mac_handle, adapter->session_id);
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700222 schedule_work(&adapter->ipv6_notifier_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800223 }
224
Dustin Brownf13b8c32017-05-19 17:23:08 -0700225exit:
Dustin Browne74003f2018-03-14 12:51:58 -0700226 hdd_exit();
Dustin Brownf13b8c32017-05-19 17:23:08 -0700227
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800228 return NOTIFY_DONE;
229}
230
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800231int wlan_hdd_ipv6_changed(struct notifier_block *nb,
232 unsigned long data, void *arg)
233{
234 int ret;
235
236 cds_ssr_protect(__func__);
237 ret = __wlan_hdd_ipv6_changed(nb, data, arg);
238 cds_ssr_unprotect(__func__);
239
240 return ret;
241}
242
243/**
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530244 * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses
245 * @idev: pointer to net device
246 * @ipv6addr: destination array to fill IPv6 addresses
247 * @ipv6addr_type: IPv6 Address type
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +0530248 * @scope_array: scope of ipv6 addr
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530249 * @count: number of IPv6 addresses
250 *
251 * This is the IPv6 utility function to populate unicast addresses.
252 *
253 * Return: 0 on success, error number otherwise.
254 */
255static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
256 uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN],
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +0530257 uint8_t *ipv6addr_type,
258 enum pmo_ns_addr_scope *scope_array,
259 uint32_t *count)
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530260{
261 struct inet6_ifaddr *ifa;
262 struct list_head *p;
263 uint32_t scope;
264
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700265 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530266 list_for_each(p, &idev->addr_list) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530267 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700268 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530269 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700270 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530271 ifa = list_entry(p, struct inet6_ifaddr, if_list);
272 if (ifa->flags & IFA_F_DADFAILED)
273 continue;
274 scope = ipv6_addr_src_scope(&ifa->addr);
275 switch (scope) {
276 case IPV6_ADDR_SCOPE_GLOBAL:
277 case IPV6_ADDR_SCOPE_LINKLOCAL:
278 qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
279 sizeof(ifa->addr.s6_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530280 ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE;
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +0530281 scope_array[*count] = pmo_ucfg_ns_addr_scope(scope);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800282 hdd_debug("Index %d scope = %s UC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530283 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
284 "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
285 *count += 1;
286 break;
287 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800288 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530289 }
290 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700291
292 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530293 return 0;
294}
295
296/**
297 * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses
298 * @idev: pointer to net device
299 * @ipv6addr: destination array to fill IPv6 addresses
300 * @ipv6addr_type: IPv6 Address type
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +0530301 * @scope_array: scope of ipv6 addr
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530302 * @count: number of IPv6 addresses
303 *
304 * This is the IPv6 utility function to populate anycast addresses.
305 *
306 * Return: 0 on success, error number otherwise.
307 */
308static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
309 uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN],
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +0530310 uint8_t *ipv6addr_type,
311 enum pmo_ns_addr_scope *scope_array,
312 uint32_t *count)
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530313{
314 struct ifacaddr6 *ifaca;
315 uint32_t scope;
316
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700317 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530318 for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530319 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700320 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530321 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700322 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530323 /* For anycast addr no DAD */
324 scope = ipv6_addr_src_scope(&ifaca->aca_addr);
325 switch (scope) {
326 case IPV6_ADDR_SCOPE_GLOBAL:
327 case IPV6_ADDR_SCOPE_LINKLOCAL:
328 qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
329 sizeof(ifaca->aca_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530330 ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE;
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +0530331 scope_array[*count] = pmo_ucfg_ns_addr_scope(scope);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800332 hdd_debug("Index %d scope = %s AC-Address: %pI6",
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530333 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
334 "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
335 *count += 1;
336 break;
337 default:
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800338 hdd_warn("The Scope %d is not supported", scope);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530339 }
340 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700341
342 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530343 return 0;
344}
345
Jeff Johnson75b737d2017-08-29 14:24:41 -0700346void hdd_enable_ns_offload(struct hdd_adapter *adapter,
Dustin Brownc1cdb712018-06-11 15:42:17 -0700347 enum pmo_offload_trigger trigger)
Dustin Brown2444ee62016-09-06 17:20:36 -0700348{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700349 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530350 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
Dustin Brownc1cdb712018-06-11 15:42:17 -0700351 struct inet6_dev *in6_dev;
352 struct pmo_ns_req *ns_req;
353 QDF_STATUS status;
354 int errno;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530355
Dustin Brown491d54b2018-03-14 12:39:11 -0700356 hdd_enter();
Dustin Brownc1cdb712018-06-11 15:42:17 -0700357
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530358 if (!psoc) {
359 hdd_err("psoc is NULL");
360 goto out;
361 }
Dustin Brown2444ee62016-09-06 17:20:36 -0700362
363 in6_dev = __in6_dev_get(adapter->dev);
364 if (NULL == in6_dev) {
365 hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530366 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700367 }
368
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530369 ns_req = qdf_mem_malloc(sizeof(*ns_req));
370 if (!ns_req) {
371 hdd_err("fail to allocate ns_req");
372 goto out;
373 }
374
375 ns_req->psoc = psoc;
Jeff Johnson1b780e42017-10-31 14:11:45 -0700376 ns_req->vdev_id = adapter->session_id;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530377 ns_req->trigger = trigger;
378 ns_req->count = 0;
379
Dustin Brown2444ee62016-09-06 17:20:36 -0700380 /* Unicast Addresses */
Dustin Brownc1cdb712018-06-11 15:42:17 -0700381 errno = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +0530382 ns_req->ipv6_addr_type, ns_req->scope,
383 &ns_req->count);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700384 if (errno) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530385 hdd_disable_ns_offload(adapter, trigger);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530386 hdd_debug("Max supported addresses: disabling NS offload");
Dustin Brownc1cdb712018-06-11 15:42:17 -0700387 goto free_req;
Dustin Brown2444ee62016-09-06 17:20:36 -0700388 }
389
390 /* Anycast Addresses */
Dustin Brownc1cdb712018-06-11 15:42:17 -0700391 errno = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +0530392 ns_req->ipv6_addr_type, ns_req->scope,
393 &ns_req->count);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700394 if (errno) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530395 hdd_disable_ns_offload(adapter, trigger);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +0530396 hdd_debug("Max supported addresses: disabling NS offload");
Dustin Brownc1cdb712018-06-11 15:42:17 -0700397 goto free_req;
Dustin Brown2444ee62016-09-06 17:20:36 -0700398 }
399
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530400 /* cache ns request */
401 status = pmo_ucfg_cache_ns_offload_req(ns_req);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700402 if (QDF_IS_STATUS_ERROR(status)) {
403 hdd_err("Failed to cache ns request; status:%d", status);
404 goto free_req;
Dustin Brown2444ee62016-09-06 17:20:36 -0700405 }
406
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530407 /* enable ns request */
408 status = pmo_ucfg_enable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700409 if (QDF_IS_STATUS_ERROR(status)) {
410 hdd_err("Failed to enable ns offload; status:%d", status);
411 goto free_req;
412 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530413
Dustin Brownc1cdb712018-06-11 15:42:17 -0700414 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
415
416free_req:
417 qdf_mem_free(ns_req);
418
419out:
420 hdd_exit();
Dustin Brown2444ee62016-09-06 17:20:36 -0700421}
422
Jeff Johnson75b737d2017-08-29 14:24:41 -0700423void hdd_disable_ns_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530424 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800425{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530426 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800427
Dustin Brown491d54b2018-03-14 12:39:11 -0700428 hdd_enter();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530429 status = pmo_ucfg_flush_ns_offload_req(adapter->hdd_vdev);
430 if (status != QDF_STATUS_SUCCESS) {
431 hdd_err("Failed to flush NS Offload");
432 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800433 }
434
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530435 status = pmo_ucfg_disable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
436 if (status != QDF_STATUS_SUCCESS)
437 hdd_err("Failed to disable NS Offload");
Dustin Brown2444ee62016-09-06 17:20:36 -0700438 else
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530439 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD,
440 SIR_OFFLOAD_DISABLE);
441out:
Dustin Browne74003f2018-03-14 12:51:58 -0700442 hdd_exit();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530443
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800444}
445
446/**
447 * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function
448 * @work: registered work item
449 *
450 * This function performs the work initially trigged by a callback
451 * from the IPv6 netdev notifier. Since this means there has been a
452 * change in IPv6 state for the interface, the NS offload is
453 * reconfigured.
454 *
455 * Return: None
456 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700457static void __hdd_ipv6_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800458{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700459 struct hdd_context *hdd_ctx;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700460 struct hdd_adapter *adapter;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700461 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800462
Dustin Brown491d54b2018-03-14 12:39:11 -0700463 hdd_enter();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800464
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700465 adapter = container_of(work, struct hdd_adapter, ipv6_notifier_work);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700466 errno = hdd_validate_adapter(adapter);
467 if (errno)
468 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800469
Dustin Brownf13b8c32017-05-19 17:23:08 -0700470 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
471 errno = wlan_hdd_validate_context(hdd_ctx);
472 if (errno)
473 goto exit;
474
475 hdd_enable_ns_offload(adapter, pmo_ipv6_change_notify);
476
477exit:
Dustin Browne74003f2018-03-14 12:51:58 -0700478 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800479}
480
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800481void hdd_ipv6_notifier_work_queue(struct work_struct *work)
482{
483 cds_ssr_protect(__func__);
484 __hdd_ipv6_notifier_work_queue(work);
485 cds_ssr_unprotect(__func__);
486}
Qiwei Cai1083f5b2018-07-02 19:10:11 +0800487#endif /* WLAN_NS_OFFLOAD */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800488
Jeff Johnson75b737d2017-08-29 14:24:41 -0700489static void hdd_enable_hw_filter(struct hdd_adapter *adapter)
Dustin Brown1224e212017-05-12 14:02:12 -0700490{
491 QDF_STATUS status;
492
Dustin Brown491d54b2018-03-14 12:39:11 -0700493 hdd_enter();
Dustin Brown1224e212017-05-12 14:02:12 -0700494
495 status = pmo_ucfg_enable_hw_filter_in_fwr(adapter->hdd_vdev);
496 if (status != QDF_STATUS_SUCCESS)
497 hdd_info("Failed to enable hardware filter");
498
Dustin Browne74003f2018-03-14 12:51:58 -0700499 hdd_exit();
Dustin Brown1224e212017-05-12 14:02:12 -0700500}
501
Jeff Johnson75b737d2017-08-29 14:24:41 -0700502static void hdd_disable_hw_filter(struct hdd_adapter *adapter)
Dustin Brown1224e212017-05-12 14:02:12 -0700503{
504 QDF_STATUS status;
505
Dustin Brown491d54b2018-03-14 12:39:11 -0700506 hdd_enter();
Dustin Brown1224e212017-05-12 14:02:12 -0700507
508 status = pmo_ucfg_disable_hw_filter_in_fwr(adapter->hdd_vdev);
509 if (status != QDF_STATUS_SUCCESS)
510 hdd_info("Failed to disable hardware filter");
511
Dustin Browne74003f2018-03-14 12:51:58 -0700512 hdd_exit();
Dustin Brown1224e212017-05-12 14:02:12 -0700513}
514
Jeff Johnson75b737d2017-08-29 14:24:41 -0700515void hdd_enable_host_offloads(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530516 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800517{
Dustin Brown491d54b2018-03-14 12:39:11 -0700518 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530519
Rajeev Kumarec1194d2017-11-16 17:30:01 -0800520 if (!ucfg_pmo_is_vdev_supports_offload(adapter->hdd_vdev)) {
Dustin Brownc1cdb712018-06-11 15:42:17 -0700521 hdd_debug("offload is not supported on vdev opmode %d",
522 adapter->device_mode);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530523 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800524 }
525
Rajeev Kumar9084cc82017-10-31 14:32:08 -0700526 if (!ucfg_pmo_is_vdev_connected(adapter->hdd_vdev)) {
Dustin Brownc1cdb712018-06-11 15:42:17 -0700527 hdd_debug("offload is not supported on disconnected vdevs");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530528 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800529 }
530
Dustin Brownc1cdb712018-06-11 15:42:17 -0700531 hdd_debug("enable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530532 hdd_enable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530533 hdd_enable_arp_offload(adapter, trigger);
534 hdd_enable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530535 hdd_enable_mc_addr_filtering(adapter, trigger);
Dustin Brown1224e212017-05-12 14:02:12 -0700536 hdd_enable_hw_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530537out:
Dustin Browne74003f2018-03-14 12:51:58 -0700538 hdd_exit();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530539
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800540}
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530541
Jeff Johnson75b737d2017-08-29 14:24:41 -0700542void hdd_disable_host_offloads(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530543 enum pmo_offload_trigger trigger)
544{
Dustin Brown491d54b2018-03-14 12:39:11 -0700545 hdd_enter();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530546
Rajeev Kumarec1194d2017-11-16 17:30:01 -0800547 if (!ucfg_pmo_is_vdev_supports_offload(adapter->hdd_vdev)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530548 hdd_info("offload is not supported on this vdev opmode: %d",
549 adapter->device_mode);
550 goto out;
551 }
552
Rajeev Kumar9084cc82017-10-31 14:32:08 -0700553 if (!ucfg_pmo_is_vdev_connected(adapter->hdd_vdev)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530554 hdd_info("vdev is not connected");
555 goto out;
556 }
557
Dustin Brownc1cdb712018-06-11 15:42:17 -0700558 hdd_debug("disable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530559 hdd_disable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530560 hdd_disable_arp_offload(adapter, trigger);
561 hdd_disable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530562 hdd_disable_mc_addr_filtering(adapter, trigger);
Dustin Brown1224e212017-05-12 14:02:12 -0700563 hdd_disable_hw_filter(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530564out:
Dustin Browne74003f2018-03-14 12:51:58 -0700565 hdd_exit();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530566
567}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800568
569/**
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800570 * hdd_lookup_ifaddr() - Lookup interface address data by name
571 * @adapter: the adapter whose name should be searched for
572 *
573 * return in_ifaddr pointer on success, NULL for failure
574 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700575static struct in_ifaddr *hdd_lookup_ifaddr(struct hdd_adapter *adapter)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800576{
577 struct in_ifaddr *ifa;
578 struct in_device *in_dev;
579
580 if (!adapter) {
581 hdd_err("adapter is null");
582 return NULL;
583 }
584
585 in_dev = __in_dev_get_rtnl(adapter->dev);
586 if (!in_dev) {
587 hdd_err("Failed to get in_device");
588 return NULL;
589 }
590
591 /* lookup address data by interface name */
592 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
593 if (!strcmp(adapter->dev->name, ifa->ifa_label))
594 return ifa;
595 }
596
597 return NULL;
598}
599
600/**
601 * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address
602 * @adapter: the adapter whose IPv4 address is desired
603 * @ipv4_addr: the address of the array to copy the IPv4 address into
604 *
605 * return: zero for success; non-zero for failure
606 */
Jeff Johnsond6d1f632017-10-06 20:06:10 -0700607static int hdd_populate_ipv4_addr(struct hdd_adapter *adapter,
608 uint8_t *ipv4_addr)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800609{
610 struct in_ifaddr *ifa;
611 int i;
612
613 if (!adapter) {
614 hdd_err("adapter is null");
615 return -EINVAL;
616 }
617
618 if (!ipv4_addr) {
619 hdd_err("ipv4_addr is null");
620 return -EINVAL;
621 }
622
623 ifa = hdd_lookup_ifaddr(adapter);
624 if (!ifa || !ifa->ifa_local) {
625 hdd_err("ipv4 address not found");
626 return -EINVAL;
627 }
628
629 /* convert u32 to byte array */
630 for (i = 0; i < 4; i++)
631 ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff;
632
633 return 0;
634}
635
636/**
637 * hdd_set_grat_arp_keepalive() - Enable grat APR keepalive
638 * @adapter: the HDD adapter to configure
639 *
640 * This configures gratuitous APR keepalive based on the adapter's current
641 * connection information, specifically IPv4 address and BSSID
642 *
643 * return: zero for success, non-zero for failure
644 */
Jeff Johnson75b737d2017-08-29 14:24:41 -0700645static int hdd_set_grat_arp_keepalive(struct hdd_adapter *adapter)
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800646{
647 QDF_STATUS status;
648 int exit_code;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700649 struct hdd_context *hdd_ctx;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700650 struct hdd_station_ctx *sta_ctx;
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800651 tSirKeepAliveReq req = {
652 .packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP,
Dustin Brownce5b3d32018-01-17 15:07:38 -0800653 .dest_macaddr = QDF_MAC_ADDR_BCAST_INIT,
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800654 };
655
656 if (!adapter) {
657 hdd_err("adapter is null");
658 return -EINVAL;
659 }
660
661 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
662 if (!hdd_ctx) {
663 hdd_err("hdd_ctx is null");
664 return -EINVAL;
665 }
666
667 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
668 if (!sta_ctx) {
669 hdd_err("sta_ctx is null");
670 return -EINVAL;
671 }
672
673 exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr);
674 if (exit_code) {
675 hdd_err("Failed to populate ipv4 address");
676 return exit_code;
677 }
678
Dustin Brown6b4643d2017-02-09 12:19:28 -0800679 /* according to RFC5227, sender/target ip address should be the same */
680 qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr,
681 sizeof(req.destIpv4Addr));
682
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800683 qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssId);
684 req.timePeriod = hdd_ctx->config->infraStaKeepAlivePeriod;
Jeff Johnson1b780e42017-10-31 14:11:45 -0700685 req.sessionId = adapter->session_id;
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800686
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800687 hdd_debug("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u",
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800688 req.hostIpv4Addr[0], req.hostIpv4Addr[1],
689 req.hostIpv4Addr[2], req.hostIpv4Addr[3]);
690
Jeff Johnson2954ded2018-06-13 16:34:49 -0700691 status = sme_set_keep_alive(hdd_ctx->mac_handle, req.sessionId, &req);
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800692 if (QDF_IS_STATUS_ERROR(status)) {
693 hdd_err("Failed to set keepalive");
694 return qdf_status_to_os_return(status);
695 }
696
697 return 0;
698}
699
700/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800701 * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function
702 * @work: registered work item
703 *
704 * This function performs the work initially trigged by a callback
705 * from the IPv4 netdev notifier. Since this means there has been a
706 * change in IPv4 state for the interface, the ARP offload is
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530707 * reconfigured. Also, Updates the HLP IE info with IP address info
708 * to fw if LFR3 is enabled
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800709 *
710 * Return: None
711 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700712static void __hdd_ipv4_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800713{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700714 struct hdd_context *hdd_ctx;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700715 struct hdd_adapter *adapter;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700716 int errno;
Jeff Johnson61b5e982018-03-15 11:33:31 -0700717 struct csr_roam_profile *roam_profile;
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530718 struct in_ifaddr *ifa;
Dustin Brownb6b0f182017-03-08 13:08:27 -0800719
Dustin Brown491d54b2018-03-14 12:39:11 -0700720 hdd_enter();
Dustin Brownb6b0f182017-03-08 13:08:27 -0800721
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700722 adapter = container_of(work, struct hdd_adapter, ipv4_notifier_work);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700723 errno = hdd_validate_adapter(adapter);
724 if (errno)
725 goto exit;
Dustin Brownb6b0f182017-03-08 13:08:27 -0800726
727 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700728 errno = wlan_hdd_validate_context(hdd_ctx);
729 if (errno)
730 goto exit;
731
732 hdd_enable_arp_offload(adapter, pmo_ipv4_change_notify);
733
Dustin Brownb6b0f182017-03-08 13:08:27 -0800734 if (hdd_ctx->config->sta_keepalive_method == HDD_STA_KEEPALIVE_GRAT_ARP)
735 hdd_set_grat_arp_keepalive(adapter);
736
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530737 hdd_debug("FILS Roaming support: %d",
738 hdd_ctx->is_fils_roaming_supported);
Jeff Johnsona0c1ca72018-03-18 14:52:03 -0700739 roam_profile = hdd_roam_profile(adapter);
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530740
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530741 ifa = hdd_lookup_ifaddr(adapter);
Vignesh Viswanathan731186f2017-09-18 13:47:37 +0530742 if (ifa && hdd_ctx->is_fils_roaming_supported)
Jeff Johnson2954ded2018-06-13 16:34:49 -0700743 sme_send_hlp_ie_info(hdd_ctx->mac_handle, adapter->session_id,
Vignesh Viswanathanc6d1e1c2017-09-18 12:32:49 +0530744 roam_profile, ifa->ifa_local);
Dustin Brownf13b8c32017-05-19 17:23:08 -0700745exit:
Dustin Browne74003f2018-03-14 12:51:58 -0700746 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800747}
748
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800749void hdd_ipv4_notifier_work_queue(struct work_struct *work)
750{
751 cds_ssr_protect(__func__);
752 __hdd_ipv4_notifier_work_queue(work);
753 cds_ssr_unprotect(__func__);
754}
755
756/**
757 * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function
758 * @nb: notifier block that was registered with the kernel
759 * @data: (unused) generic data that was registered with the kernel
760 * @arg: (unused) generic argument that was registered with the kernel
761 *
762 * This is a callback function that is registered with the kernel via
763 * register_inetaddr_notifier() which allows the driver to be
764 * notified when there is an IPv4 address change.
765 *
766 * Return: NOTIFY_DONE to indicate we don't care what happens with
767 * other callbacks
768 */
769static int __wlan_hdd_ipv4_changed(struct notifier_block *nb,
770 unsigned long data, void *arg)
771{
772 struct in_ifaddr *ifa = (struct in_ifaddr *)arg;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800773 struct net_device *ndev = ifa->ifa_dev->dev;
Jeff Johnson75b737d2017-08-29 14:24:41 -0700774 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700775 struct hdd_context *hdd_ctx;
Dustin Brownf13b8c32017-05-19 17:23:08 -0700776 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800777
Dustin Brownfdf17c12018-03-14 12:55:34 -0700778 hdd_enter_dev(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530779
Dustin Brownf13b8c32017-05-19 17:23:08 -0700780 errno = hdd_validate_adapter(adapter);
781 if (errno)
782 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800783
Dustin Brownf13b8c32017-05-19 17:23:08 -0700784 if (adapter->dev == ndev &&
785 (adapter->device_mode == QDF_STA_MODE ||
786 adapter->device_mode == QDF_P2P_CLIENT_MODE ||
787 adapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800788
Dustin Brownf13b8c32017-05-19 17:23:08 -0700789 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
790 errno = wlan_hdd_validate_context(hdd_ctx);
791 if (errno)
792 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793
Nachiket Kukadec9045fe2017-06-19 15:14:43 +0530794 /* Ignore if the interface is down */
795 if (!(ndev->flags & IFF_UP)) {
796 hdd_err("Rcvd change addr request on %s(flags 0x%X)",
797 ndev->name, ndev->flags);
798 hdd_err("NETDEV Interface is down, ignoring...");
799 goto exit;
800 }
Padma, Santhosh Kumar8392fb42017-03-17 12:35:27 +0530801 hdd_debug("invoking sme_dhcp_done_ind");
Jeff Johnson2954ded2018-06-13 16:34:49 -0700802 sme_dhcp_done_ind(hdd_ctx->mac_handle, adapter->session_id);
Abhishek Singhca408032016-09-13 15:26:12 +0530803
Dustin Brownf13b8c32017-05-19 17:23:08 -0700804 if (!hdd_ctx->config->fhostArpOffload) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -0800805 hdd_debug("Offload not enabled ARPOffload=%d",
Dustin Brownf13b8c32017-05-19 17:23:08 -0700806 hdd_ctx->config->fhostArpOffload);
807 goto exit;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800808 }
809
Dustin Brownf13b8c32017-05-19 17:23:08 -0700810 ifa = hdd_lookup_ifaddr(adapter);
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800811 if (ifa && ifa->ifa_local)
Jeff Johnsonb527ebe2017-10-28 13:14:03 -0700812 schedule_work(&adapter->ipv4_notifier_work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800813 }
Dustin Brownf13b8c32017-05-19 17:23:08 -0700814
815exit:
Dustin Browne74003f2018-03-14 12:51:58 -0700816 hdd_exit();
Dustin Brownf13b8c32017-05-19 17:23:08 -0700817
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800818 return NOTIFY_DONE;
819}
820
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800821int wlan_hdd_ipv4_changed(struct notifier_block *nb,
822 unsigned long data, void *arg)
823{
824 int ret;
825
826 cds_ssr_protect(__func__);
827 ret = __wlan_hdd_ipv4_changed(nb, data, arg);
828 cds_ssr_unprotect(__func__);
829
830 return ret;
831}
832
833/**
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530834 * hdd_get_ipv4_local_interface() - get ipv4 local interafce from iface list
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700835 * @adapter: Adapter context for which ARP offload is to be configured
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800836 *
837 * Return:
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530838 * ifa - on successful operation,
839 * NULL - on failure of operation
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840 */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530841static struct in_ifaddr *hdd_get_ipv4_local_interface(
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700842 struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800843{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530844 struct in_ifaddr **ifap = NULL;
845 struct in_ifaddr *ifa = NULL;
846 struct in_device *in_dev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800847
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700848 in_dev = __in_dev_get_rtnl(adapter->dev);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530849 if (in_dev) {
850 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
851 ifap = &ifa->ifa_next) {
Jeff Johnsonf6d24282017-10-02 13:25:25 -0700852 if (!strcmp(adapter->dev->name, ifa->ifa_label)) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530853 /* if match break */
854 return ifa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800855 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800856 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530857 }
858 ifa = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800859
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530860 return ifa;
861}
862
Jeff Johnson75b737d2017-08-29 14:24:41 -0700863void hdd_enable_arp_offload(struct hdd_adapter *adapter,
Dustin Brownc1cdb712018-06-11 15:42:17 -0700864 enum pmo_offload_trigger trigger)
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530865{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -0700866 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530867 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
868 QDF_STATUS status;
Dustin Brownc1cdb712018-06-11 15:42:17 -0700869 struct pmo_arp_req *arp_req;
870 struct in_ifaddr *ifa;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530871
Dustin Brown491d54b2018-03-14 12:39:11 -0700872 hdd_enter();
Dustin Brownc1cdb712018-06-11 15:42:17 -0700873
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530874 arp_req = qdf_mem_malloc(sizeof(*arp_req));
875 if (!arp_req) {
876 hdd_err("cannot allocate arp_req");
877 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878 }
Jeff Johnson68755312017-02-10 11:46:55 -0800879
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530880 arp_req->psoc = psoc;
Jeff Johnson1b780e42017-10-31 14:11:45 -0700881 arp_req->vdev_id = adapter->session_id;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530882 arp_req->trigger = trigger;
Jeff Johnson68755312017-02-10 11:46:55 -0800883
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530884 ifa = hdd_get_ipv4_local_interface(adapter);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700885 if (!ifa || !ifa->ifa_local) {
Dustin Brown5e89ef82018-03-14 11:50:23 -0700886 hdd_info("IP Address is not assigned");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530887 status = QDF_STATUS_NOT_INITIALIZED;
Dustin Brownc1cdb712018-06-11 15:42:17 -0700888 goto free_req;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530889 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530890
Dustin Brownc1cdb712018-06-11 15:42:17 -0700891 arp_req->ipv4_addr = (uint32_t)ifa->ifa_local;
892
893 status = pmo_ucfg_cache_arp_offload_req(arp_req);
894 if (QDF_IS_STATUS_ERROR(status)) {
Dustin Brown0127a732018-07-19 14:06:34 -0700895 hdd_err("failed to cache arp offload req; status:%d", status);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700896 goto free_req;
897 }
898
899 status = pmo_ucfg_enable_arp_offload_in_fwr(adapter->hdd_vdev, trigger);
900 if (QDF_IS_STATUS_ERROR(status)) {
Dustin Brown0127a732018-07-19 14:06:34 -0700901 hdd_err("failed arp offload config in fw; status:%d", status);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700902 goto free_req;
903 }
904
905 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD, PMO_OFFLOAD_ENABLE);
906
907free_req:
908 qdf_mem_free(arp_req);
909
910out:
911 hdd_exit();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530912}
913
Jeff Johnson75b737d2017-08-29 14:24:41 -0700914void hdd_disable_arp_offload(struct hdd_adapter *adapter,
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530915 enum pmo_offload_trigger trigger)
916{
917 QDF_STATUS status;
918
Dustin Brown491d54b2018-03-14 12:39:11 -0700919 hdd_enter();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530920 status = pmo_ucfg_flush_arp_offload_req(adapter->hdd_vdev);
921 if (status != QDF_STATUS_SUCCESS) {
922 hdd_err("Failed to flush arp Offload");
923 goto out;
Jeff Johnson68755312017-02-10 11:46:55 -0800924 }
925
Jeff Johnsond6d1f632017-10-06 20:06:10 -0700926 status = pmo_ucfg_disable_arp_offload_in_fwr(adapter->hdd_vdev,
927 trigger);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530928 if (status == QDF_STATUS_SUCCESS)
929 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD,
930 PMO_OFFLOAD_DISABLE);
931 else
932 hdd_info("fail to disable arp offload");
933out:
Dustin Browne74003f2018-03-14 12:51:58 -0700934 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800935}
936
Jeff Johnson75b737d2017-08-29 14:24:41 -0700937void hdd_enable_mc_addr_filtering(struct hdd_adapter *adapter,
Dustin Brown0127a732018-07-19 14:06:34 -0700938 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800939{
Jeff Johnson399c6272017-08-30 10:51:00 -0700940 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530941 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800942
Dustin Brown491d54b2018-03-14 12:39:11 -0700943 hdd_enter();
Dustin Brown0127a732018-07-19 14:06:34 -0700944
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530945 if (wlan_hdd_validate_context(hdd_ctx))
946 goto out;
Ravi Joshi24477b72016-07-19 15:45:09 -0700947
Dustin Brown0127a732018-07-19 14:06:34 -0700948 if (!hdd_adapter_is_connected_sta(adapter))
949 goto out;
950
951 status = pmo_ucfg_enable_mc_addr_filtering_in_fwr(hdd_ctx->hdd_psoc,
952 adapter->session_id,
953 trigger);
Dustin Brownc1cdb712018-06-11 15:42:17 -0700954 if (QDF_IS_STATUS_ERROR(status))
Dustin Brown0127a732018-07-19 14:06:34 -0700955 hdd_err("failed to enable mc list; status:%d", status);
956
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530957out:
Dustin Browne74003f2018-03-14 12:51:58 -0700958 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800959}
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530960
Jeff Johnson75b737d2017-08-29 14:24:41 -0700961void hdd_disable_mc_addr_filtering(struct hdd_adapter *adapter,
Dustin Brown0127a732018-07-19 14:06:34 -0700962 enum pmo_offload_trigger trigger)
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530963{
Jeff Johnson399c6272017-08-30 10:51:00 -0700964 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Dustin Brown0127a732018-07-19 14:06:34 -0700965 QDF_STATUS status;
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530966
Dustin Brown491d54b2018-03-14 12:39:11 -0700967 hdd_enter();
Dustin Brown0127a732018-07-19 14:06:34 -0700968
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530969 if (wlan_hdd_validate_context(hdd_ctx))
970 goto out;
971
Dustin Brown0127a732018-07-19 14:06:34 -0700972 if (!hdd_adapter_is_connected_sta(adapter))
973 goto out;
974
975 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(hdd_ctx->hdd_psoc,
976 adapter->session_id,
977 trigger);
978 if (QDF_IS_STATUS_ERROR(status))
979 hdd_err("failed to disable mc list; status:%d", status);
Dustin Brown0f874482018-06-13 14:39:22 -0700980
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530981out:
Dustin Browne74003f2018-03-14 12:51:58 -0700982 hdd_exit();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530983}
984
985int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config)
986{
987 QDF_STATUS status;
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530988
Dustin Brown491d54b2018-03-14 12:39:11 -0700989 hdd_enter();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530990 status = pmo_ucfg_cache_mc_addr_list(mc_list_config);
Dustin Browne74003f2018-03-14 12:51:58 -0700991 hdd_exit();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530992
Dustin Brown0f874482018-06-13 14:39:22 -0700993 return qdf_status_to_os_return(status);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530994}
995
Jeff Johnson75b737d2017-08-29 14:24:41 -0700996void hdd_disable_and_flush_mc_addr_list(struct hdd_adapter *adapter,
Dustin Brown0127a732018-07-19 14:06:34 -0700997 enum pmo_offload_trigger trigger)
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530998{
Jeff Johnson399c6272017-08-30 10:51:00 -0700999 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Dustin Brown0127a732018-07-19 14:06:34 -07001000 QDF_STATUS status;
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301001
Dustin Brown491d54b2018-03-14 12:39:11 -07001002 hdd_enter();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301003
Dustin Brown0127a732018-07-19 14:06:34 -07001004 if (!hdd_adapter_is_connected_sta(adapter))
1005 goto flush_mc_list;
1006
1007 /* disable mc list first because the mc list is cached in PMO */
1008 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(hdd_ctx->hdd_psoc,
1009 adapter->session_id,
1010 trigger);
1011 if (QDF_IS_STATUS_ERROR(status))
1012 hdd_err("failed to disable mc list; status:%d", status);
1013
1014flush_mc_list:
1015 status = pmo_ucfg_flush_mc_addr_list(hdd_ctx->hdd_psoc,
1016 adapter->session_id);
1017 if (QDF_IS_STATUS_ERROR(status))
1018 hdd_err("failed to flush mc list; status:%d", status);
Dustin Brown0f874482018-06-13 14:39:22 -07001019
Dustin Browne74003f2018-03-14 12:51:58 -07001020 hdd_exit();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301021
1022 return;
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +05301023}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001024
1025/**
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001026 * hdd_update_conn_state_mask(): record info needed by wma_suspend_req
1027 * @adapter: adapter to get info from
1028 * @conn_state_mask: mask of connection info
1029 *
1030 * currently only need to send connection info.
1031 */
Jeff Johnsond6d1f632017-10-06 20:06:10 -07001032static void hdd_update_conn_state_mask(struct hdd_adapter *adapter,
1033 uint32_t *conn_state_mask)
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001034{
1035
1036 eConnectionState connState;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07001037 struct hdd_station_ctx *sta_ctx;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301038
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001039 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301040
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001041 connState = sta_ctx->conn_info.connState;
1042
1043 if (connState == eConnectionState_Associated ||
1044 connState == eConnectionState_IbssConnected)
Jeff Johnson1b780e42017-10-31 14:11:45 -07001045 *conn_state_mask |= (1 << adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046}
1047
1048/**
1049 * hdd_suspend_wlan() - Driver suspend function
1050 * @callback: Callback function to invoke when driver is ready to suspend
1051 * @callbackContext: Context to pass back to @callback function
1052 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301053 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301055static int
1056hdd_suspend_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001057{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001058 struct hdd_context *hdd_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301059 QDF_STATUS status;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001060 struct hdd_adapter *adapter = NULL;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001061 uint32_t conn_state_mask = 0;
Jeff Johnson4f7f7c62017-10-05 08:53:41 -07001062
Jeff Johnsonc3273322016-07-06 15:28:17 -07001063 hdd_info("WLAN being suspended by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001064
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001065 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1066 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001067 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301068 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001069 }
1070
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301071 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001072 hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001073 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301074 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001075 }
1076
Dustin Brown920397d2017-12-13 16:27:50 -08001077 hdd_for_each_adapter(hdd_ctx, adapter) {
Dustin Brown867ce6d2018-07-19 16:03:33 -07001078 if (wlan_hdd_validate_session_id(adapter->session_id))
Dustin Brown920397d2017-12-13 16:27:50 -08001079 continue;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001080
1081 /* stop all TX queues before suspend */
Dustin Brownc1cdb712018-06-11 15:42:17 -07001082 hdd_debug("Disabling queues for dev mode %s",
1083 hdd_device_mode_to_string(adapter->device_mode));
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001084 wlan_hdd_netif_queue_control(adapter,
Himanshu Agarwal865201d2017-04-12 15:45:31 +05301085 WLAN_STOP_ALL_NETIF_QUEUE,
1086 WLAN_CONTROL_PATH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001087
Hanumanth Reddy Pothula3def8942017-10-05 16:19:36 +05301088 if (adapter->device_mode == QDF_STA_MODE)
1089 status = hdd_enable_default_pkt_filters(adapter);
1090
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001091 /* Configure supported OffLoads */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001092 hdd_enable_host_offloads(adapter, pmo_apps_suspend);
1093 hdd_update_conn_state_mask(adapter, &conn_state_mask);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001094 }
1095
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001096 status = pmo_ucfg_psoc_user_space_suspend_req(hdd_ctx->hdd_psoc,
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301097 QDF_SYSTEM_SUSPEND);
1098 if (status != QDF_STATUS_SUCCESS)
1099 return -EAGAIN;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001100
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001101 hdd_ctx->hdd_wlan_suspended = true;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301102 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001103
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301104 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105}
1106
1107/**
1108 * hdd_resume_wlan() - Driver resume function
1109 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301110 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001111 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301112static int hdd_resume_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001113{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001114 struct hdd_context *hdd_ctx;
Dustin Brownc1cdb712018-06-11 15:42:17 -07001115 struct hdd_adapter *adapter;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301116 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117
Dustin Brown2d228232016-09-22 15:06:19 -07001118 hdd_info("WLAN being resumed by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001119
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001120 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1121 if (!hdd_ctx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001122 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301123 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001124 }
1125
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301126 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001127 hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001128 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301129 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001130 }
1131
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001132 hdd_ctx->hdd_wlan_suspended = false;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301133 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001134
1135 /*loop through all adapters. Concurrency */
Dustin Brown920397d2017-12-13 16:27:50 -08001136 hdd_for_each_adapter(hdd_ctx, adapter) {
Dustin Brown63500612018-08-07 11:36:09 -07001137 if (wlan_hdd_validate_session_id(adapter->session_id))
Dustin Brown920397d2017-12-13 16:27:50 -08001138 continue;
Dustin Brown63500612018-08-07 11:36:09 -07001139
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301140 /* Disable supported OffLoads */
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001141 hdd_disable_host_offloads(adapter, pmo_apps_resume);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142
1143 /* wake the tx queues */
Dustin Brownc1cdb712018-06-11 15:42:17 -07001144 hdd_debug("Enabling queues for dev mode %s",
1145 hdd_device_mode_to_string(adapter->device_mode));
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001146 wlan_hdd_netif_queue_control(adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001147 WLAN_WAKE_ALL_NETIF_QUEUE,
1148 WLAN_CONTROL_PATH);
1149
Hanumanth Reddy Pothula3def8942017-10-05 16:19:36 +05301150 if (adapter->device_mode == QDF_STA_MODE)
1151 status = hdd_disable_default_pkt_filters(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001152 }
Dustin Brown920397d2017-12-13 16:27:50 -08001153
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301154 ucfg_ipa_resume(hdd_ctx->hdd_pdev);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001155 status = pmo_ucfg_psoc_user_space_resume_req(hdd_ctx->hdd_psoc,
Dustin Brownc1cdb712018-06-11 15:42:17 -07001156 QDF_SYSTEM_SUSPEND);
1157 if (QDF_IS_STATUS_ERROR(status))
1158 return qdf_status_to_os_return(status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001159
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301160 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001161}
1162
Komal Seelam78ff65a2016-08-18 15:25:24 +05301163void hdd_svc_fw_shutdown_ind(struct device *dev)
1164{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001165 struct hdd_context *hdd_ctx;
Komal Seelam78ff65a2016-08-18 15:25:24 +05301166
1167 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1168
1169 hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
1170 WLAN_SVC_FW_SHUTDOWN_IND,
1171 NULL, 0) : 0;
1172}
1173
1174/**
Arun Khandavallicc544b32017-01-30 19:52:16 +05301175 * hdd_ssr_restart_sap() - restart sap on SSR
1176 * @hdd_ctx: hdd context
1177 *
1178 * Return: nothing
1179 */
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001180static void hdd_ssr_restart_sap(struct hdd_context *hdd_ctx)
Arun Khandavallicc544b32017-01-30 19:52:16 +05301181{
Jeff Johnson75b737d2017-08-29 14:24:41 -07001182 struct hdd_adapter *adapter;
Arun Khandavallicc544b32017-01-30 19:52:16 +05301183
Dustin Brown491d54b2018-03-14 12:39:11 -07001184 hdd_enter();
Arun Khandavallicc544b32017-01-30 19:52:16 +05301185
Dustin Brown920397d2017-12-13 16:27:50 -08001186 hdd_for_each_adapter(hdd_ctx, adapter) {
1187 if (adapter->device_mode == QDF_SAP_MODE) {
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001188 if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001189 hdd_debug("Restart prev SAP session");
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001190 wlan_hdd_start_sap(adapter, true);
1191 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05301192 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05301193 }
1194
Dustin Browne74003f2018-03-14 12:51:58 -07001195 hdd_exit();
Arun Khandavallicc544b32017-01-30 19:52:16 +05301196}
1197
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301198QDF_STATUS hdd_wlan_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001199{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001200 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001201 p_cds_sched_context cds_sched_context = NULL;
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001202 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001203
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001204 hdd_info("WLAN driver shutting down!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001205
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001206 /* Get the HDD context. */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001207 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1208 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001209 hdd_err("HDD context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301210 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001211 }
1212
Rajeev Kumarc27efb62018-08-31 14:21:22 -07001213 hdd_bus_bw_compute_timer_stop(hdd_ctx);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001214 policy_mgr_clear_concurrent_session_count(hdd_ctx->hdd_psoc);
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301215
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001216 hdd_debug("Invoking packetdump deregistration API");
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301217 wlan_deregister_txrx_packetdump();
jitiphilfb410612018-03-26 22:37:56 +05301218
1219 /*
1220 * After SSR, FW clear its txrx stats. In host,
1221 * as adapter is intact so those counts are still
1222 * available. Now if agains Set stats command comes,
1223 * then host will increment its counts start from its
1224 * last saved value, i.e., count before SSR, and FW will
1225 * increment its count from 0. This will finally sends a
1226 * mismatch of packet counts b/w host and FW to framework
1227 * that will create ambiquity. Therfore, Resetting the host
1228 * counts here so that after SSR both FW and host start
1229 * increment their counts from 0.
1230 */
1231 hdd_reset_all_adapters_connectivity_stats(hdd_ctx);
1232
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001233 hdd_reset_all_adapters(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001234
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301235 /* Flush cached rx frame queue */
Manikandan Mohan8b4e2012017-03-22 11:15:55 -07001236 if (soc)
1237 cdp_flush_cache_rx_queue(soc);
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301238
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301239 /* De-register the HDD callbacks */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001240 hdd_deregister_cb(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001241
1242 cds_sched_context = get_cds_sched_ctxt();
1243
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001244 if (hdd_ctx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001245 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001246 hdd_ctx->is_scheduler_suspended = false;
Jeff Johnson214671b2017-10-30 19:45:23 -07001247 hdd_ctx->is_wiphy_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001248 }
Mohit Khanna70322002018-05-15 19:21:32 -07001249
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001250 if (true == hdd_ctx->is_ol_rx_thread_suspended) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001251 complete(&cds_sched_context->ol_resume_rx_event);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001252 hdd_ctx->is_ol_rx_thread_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001253 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001254
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001255 hdd_wlan_stop_modules(hdd_ctx, false);
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301256
Dustin Brown86d196b2018-08-02 11:51:49 -07001257 hdd_bus_bandwidth_deinit(hdd_ctx);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001258 hdd_lpass_notify_stop(hdd_ctx);
Yuanyuan Liu3e918e52016-08-17 15:41:35 -07001259
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001260 hdd_info("WLAN driver shutdown complete");
Yue Ma2be12872017-06-02 13:06:58 -07001261
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301262 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001263}
1264
Sen, Devendra154b3c42017-02-13 20:44:15 +05301265#ifdef FEATURE_WLAN_DIAG_SUPPORT
1266/**
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301267 * hdd_wlan_ssr_reinit_event()- send ssr reinit state
1268 *
1269 * This Function send send ssr reinit state diag event
1270 *
1271 * Return: void.
1272 */
Sen, Devendra154b3c42017-02-13 20:44:15 +05301273static void hdd_wlan_ssr_reinit_event(void)
1274{
1275 WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit);
1276 qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit));
1277 ssr_reinit.status = SSR_SUB_SYSTEM_REINIT;
1278 WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit,
1279 EVENT_WLAN_SSR_REINIT_SUBSYSTEM);
1280}
1281#else
1282static inline void hdd_wlan_ssr_reinit_event(void)
1283{
1284
1285}
1286#endif
1287
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001288/**
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301289 * hdd_send_default_scan_ies - send default scan ies to fw
1290 *
1291 * This function is used to send default scan ies to fw
1292 * in case of wlan re-init
1293 *
1294 * Return: void
1295 */
1296static void hdd_send_default_scan_ies(struct hdd_context *hdd_ctx)
1297{
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301298 struct hdd_adapter *adapter;
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301299
Dustin Brown920397d2017-12-13 16:27:50 -08001300 hdd_for_each_adapter(hdd_ctx, adapter) {
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301301 if (hdd_is_interface_up(adapter) &&
1302 (adapter->device_mode == QDF_STA_MODE ||
Hanumanth Reddy Pothula53dec122017-12-12 17:08:18 +05301303 adapter->device_mode == QDF_P2P_DEVICE_MODE) &&
1304 adapter->scan_info.default_scan_ies) {
Jeff Johnson2954ded2018-06-13 16:34:49 -07001305 sme_set_default_scan_ie(hdd_ctx->mac_handle,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001306 adapter->session_id,
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301307 adapter->scan_info.default_scan_ies,
1308 adapter->scan_info.default_scan_ies_len);
1309 }
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301310 }
1311}
1312
Arun Khandavallifae92942016-08-01 13:31:08 +05301313QDF_STATUS hdd_wlan_re_init(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001314{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001315 struct hdd_context *hdd_ctx = NULL;
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001316 struct hdd_adapter *adapter;
Arun Khandavallifae92942016-08-01 13:31:08 +05301317 int ret;
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301318 bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001319
1320 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1321
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001322 /* Get the HDD context */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001323 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1324 if (!hdd_ctx) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001325 hdd_err("HDD context is Null");
Sourav Mohapatrab1260132018-08-21 14:42:55 +05301326 goto err_ctx_null;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001327 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001328 bug_on_reinit_failure = hdd_ctx->config->bug_on_reinit_failure;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001329
Sourav Mohapatra92ea8d62018-02-05 10:03:10 +05301330 adapter = hdd_get_first_valid_adapter(hdd_ctx);
1331 if (!adapter)
1332 hdd_err("Failed to get adapter");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001333
Nirav Shahd21a2e32018-04-20 16:34:43 +05301334 hdd_dp_trace_init(hdd_ctx->config);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001335 hdd_bus_bandwidth_init(hdd_ctx);
Prashanth Bhattaab004382016-10-11 16:08:11 -07001336
Dustin Browne7e71d32018-05-11 16:00:08 -07001337 ret = hdd_wlan_start_modules(hdd_ctx, true);
Arun Khandavallifae92942016-08-01 13:31:08 +05301338 if (ret) {
1339 hdd_err("Failed to start wlan after error");
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301340 goto err_re_init;
Arun Khandavallifae92942016-08-01 13:31:08 +05301341 }
1342
Ryan Hsuaadba072018-04-20 13:01:53 -07001343 hdd_update_hw_sw_info(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001344
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001345 wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
Wu Gao36717432016-11-21 15:09:48 +08001346 WLAN_SVC_FW_CRASHED_IND, NULL, 0);
1347
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001348 /* Restart all adapters */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001349 hdd_start_all_adapters(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001350
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001351 hdd_ctx->last_scan_reject_session_id = 0xFF;
1352 hdd_ctx->last_scan_reject_reason = 0;
1353 hdd_ctx->last_scan_reject_timestamp = 0;
1354 hdd_ctx->scan_reject_cnt = 0;
Sreelakshmi Konamkib53c6292017-03-01 13:13:23 +05301355
Selvaraj, Sridhar1c487562017-04-19 14:29:07 +05301356 hdd_set_roaming_in_progress(false);
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001357 complete(&adapter->roaming_comp_var);
Jeff Johnson59b19312017-11-02 21:14:33 -07001358 hdd_ctx->bt_coex_mode_set = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001359
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001360 /* Allow the phone to go to sleep */
1361 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05301362 /* set chip power save failure detected callback */
Jeff Johnson2954ded2018-06-13 16:34:49 -07001363 sme_set_chip_pwr_save_fail_cb(hdd_ctx->mac_handle,
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05301364 hdd_chip_pwr_save_fail_detected_cb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001365
yeshwanth sriram guntukaea63f632017-08-30 19:31:56 +05301366 hdd_send_default_scan_ies(hdd_ctx);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001367 hdd_info("WLAN host driver reinitiation completed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001368
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001369 if (hdd_ctx->config->sap_internal_restart)
1370 hdd_ssr_restart_sap(hdd_ctx);
Hanumanth Reddy Pothula2a8a7402017-07-03 14:06:11 +05301371
Sen, Devendra154b3c42017-02-13 20:44:15 +05301372 hdd_wlan_ssr_reinit_event();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301373 return QDF_STATUS_SUCCESS;
Sourav Mohapatrab1260132018-08-21 14:42:55 +05301374
1375err_re_init:
1376 hdd_bus_bandwidth_deinit(hdd_ctx);
1377 qdf_dp_trace_deinit();
1378
1379err_ctx_null:
1380 /* Allow the phone to go to sleep */
1381 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1382 if (bug_on_reinit_failure)
1383 QDF_BUG(0);
1384 return -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001385}
1386
Jeff Johnson75b737d2017-08-29 14:24:41 -07001387int wlan_hdd_set_powersave(struct hdd_adapter *adapter,
Dustin Brownf660fb42016-09-09 12:04:00 -07001388 bool allow_power_save, uint32_t timeout)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001389{
Jeff Johnson2954ded2018-06-13 16:34:49 -07001390 mac_handle_t mac_handle;
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001391 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001392
1393 if (NULL == adapter) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001394 hdd_err("Adapter NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001395 return -ENODEV;
1396 }
1397
1398 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1399 if (!hdd_ctx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001400 hdd_err("hdd context is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001401 return -EINVAL;
1402 }
1403
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001404 hdd_debug("Allow power save: %d", allow_power_save);
Jeff Johnson2954ded2018-06-13 16:34:49 -07001405 mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001406
Dustin Brown84411b02017-07-21 16:44:44 -07001407 /*
1408 * This is a workaround for defective AP's that send a disassoc
1409 * immediately after WPS connection completes. Defer powersave by a
1410 * small amount if the affected AP is detected.
1411 */
1412 if (allow_power_save &&
1413 adapter->device_mode == QDF_STA_MODE &&
Jeff Johnsonb9424862017-10-30 08:49:35 -07001414 !adapter->session.station.ap_supports_immediate_power_save) {
Dustin Brown84411b02017-07-21 16:44:44 -07001415 timeout = AUTO_PS_DEFER_TIMEOUT_MS;
1416 hdd_debug("Defer power-save due to AP spec non-conformance");
Krunal Soni364e0872017-05-10 21:24:34 -07001417 }
1418
Dustin Brownf660fb42016-09-09 12:04:00 -07001419 if (allow_power_save) {
1420 if (QDF_STA_MODE == adapter->device_mode ||
1421 QDF_P2P_CLIENT_MODE == adapter->device_mode) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001422 hdd_debug("Disabling Auto Power save timer");
Jeff Johnson2954ded2018-06-13 16:34:49 -07001423 sme_ps_disable_auto_ps_timer(mac_handle,
1424 adapter->session_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001425 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001426
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001427 if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001428 hdd_debug("Wlan driver Entering Power save");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001429
1430 /*
1431 * Enter Power Save command received from GUI
1432 * this means DHCP is completed
1433 */
Yeshwanth Sriram Guntukaae03c432017-11-12 13:31:02 +05301434 if (timeout)
Jeff Johnson2954ded2018-06-13 16:34:49 -07001435 sme_ps_enable_auto_ps_timer(mac_handle,
Yeshwanth Sriram Guntukaae03c432017-11-12 13:31:02 +05301436 adapter->session_id,
1437 timeout);
1438 else
Jeff Johnson2954ded2018-06-13 16:34:49 -07001439 sme_ps_enable_disable(mac_handle,
1440 adapter->session_id,
Yeshwanth Sriram Guntukaae03c432017-11-12 13:31:02 +05301441 SME_PS_ENABLE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001442 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001443 hdd_debug("Power Save is not enabled in the cfg");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001444 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001445 } else {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001446 hdd_debug("Wlan driver Entering Full Power");
Dustin Brownf660fb42016-09-09 12:04:00 -07001447
1448 /*
1449 * Enter Full power command received from GUI
1450 * this means we are disconnected
1451 */
Jeff Johnson2954ded2018-06-13 16:34:49 -07001452 sme_ps_disable_auto_ps_timer(mac_handle,
1453 adapter->session_id);
1454 sme_ps_enable_disable(mac_handle, adapter->session_id,
1455 SME_PS_DISABLE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001456 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001457
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001458 return 0;
1459}
1460
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001461static void wlan_hdd_print_suspend_fail_stats(struct hdd_context *hdd_ctx)
Dustin Brown105d7902016-10-03 16:27:59 -07001462{
Dustin Brownd9322482017-01-09 12:46:03 -08001463 struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301464
Dustin Brown105d7902016-10-03 16:27:59 -07001465 hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d",
Dustin Brownd9322482017-01-09 12:46:03 -08001466 stats->suspend_fail[SUSPEND_FAIL_IPA],
1467 stats->suspend_fail[SUSPEND_FAIL_RADAR],
1468 stats->suspend_fail[SUSPEND_FAIL_ROAM],
1469 stats->suspend_fail[SUSPEND_FAIL_SCAN],
1470 stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]);
Dustin Brown105d7902016-10-03 16:27:59 -07001471}
1472
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001473void wlan_hdd_inc_suspend_stats(struct hdd_context *hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001474 enum suspend_fail_reason reason)
1475{
1476 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001477 hdd_ctx->suspend_resume_stats.suspend_fail[reason]++;
Dustin Brown105d7902016-10-03 16:27:59 -07001478 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
1479}
1480
Dustin Brown5fbb1052017-08-11 17:25:51 -07001481#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
1482static inline void
1483hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
1484{
1485 cfg80211_sched_scan_results(wiphy);
1486}
1487#else
1488static inline void
1489hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid)
1490{
1491 cfg80211_sched_scan_results(wiphy, reqid);
1492}
1493#endif
1494
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001495/**
1496 * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1497 * @wiphy: Pointer to wiphy
1498 *
1499 * This API is called when cfg80211 driver resumes driver updates
1500 * latest sched_scan scan result(if any) to cfg80211 database
1501 *
1502 * Return: integer status
1503 */
1504static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1505{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001506 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301507 QDF_STATUS status = QDF_STATUS_SUCCESS;
Dustin Brownd9322482017-01-09 12:46:03 -08001508 int exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001509 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1510
Dustin Brown491d54b2018-03-14 12:39:11 -07001511 hdd_enter();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001512
Dustin Brownd9322482017-01-09 12:46:03 -08001513 if (cds_is_driver_recovering()) {
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001514 hdd_debug("Driver is recovering; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001515 exit_code = 0;
1516 goto exit_with_code;
1517 }
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001518
Anurag Chouhan6d760662016-02-20 16:05:43 +05301519 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001520 hdd_err("Command not allowed in FTM mode");
Dustin Brownd9322482017-01-09 12:46:03 -08001521 exit_code = -EINVAL;
1522 goto exit_with_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001523 }
1524
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001525 exit_code = wlan_hdd_validate_context(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001526 if (exit_code) {
1527 hdd_err("Invalid HDD context");
1528 goto exit_with_code;
1529 }
Arun Khandavallifae92942016-08-01 13:31:08 +05301530
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001531 mutex_lock(&hdd_ctx->iface_change_lock);
1532 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1533 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001534 hdd_debug("Driver is not enabled; Skipping resume");
Dustin Brownd9322482017-01-09 12:46:03 -08001535 exit_code = 0;
1536 goto exit_with_code;
Arun Khandavallifae92942016-08-01 13:31:08 +05301537 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001538 mutex_unlock(&hdd_ctx->iface_change_lock);
Dustin Brownd9322482017-01-09 12:46:03 -08001539
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001540 pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_MEDIUM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001541
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301542 status = hdd_resume_wlan();
1543 if (status != QDF_STATUS_SUCCESS) {
1544 exit_code = 0;
1545 goto exit_with_code;
1546 }
Rajeev Kumareada0d02016-12-08 17:44:17 -08001547 /* Resume control path scheduler */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001548 if (hdd_ctx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001549 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001550 hdd_ctx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001551 }
Mohit Khanna70322002018-05-15 19:21:32 -07001552
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001553 /* Resume tlshim Rx thread */
Mohit Khanna70322002018-05-15 19:21:32 -07001554 if (hdd_ctx->enable_rxthread && hdd_ctx->is_ol_rx_thread_suspended) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001555 complete(&cds_sched_context->ol_resume_rx_event);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001556 hdd_ctx->is_ol_rx_thread_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001557 }
Mohit Khanna70322002018-05-15 19:21:32 -07001558
1559 if (hdd_ctx->enable_dp_rx_threads)
1560 dp_txrx_resume(cds_get_context(QDF_MODULE_ID_SOC));
1561
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001562
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301563 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301564 TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
Jeff Johnson214671b2017-10-30 19:45:23 -07001565 NO_SESSION, hdd_ctx->is_wiphy_suspended));
Jeff Johnson214671b2017-10-30 19:45:23 -07001566 hdd_ctx->is_wiphy_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001567
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001568 hdd_ctx->suspend_resume_stats.resumes++;
Dustin Brownd9322482017-01-09 12:46:03 -08001569 exit_code = 0;
1570
1571exit_with_code:
Dustin Browne74003f2018-03-14 12:51:58 -07001572 hdd_exit();
Dustin Brownd9322482017-01-09 12:46:03 -08001573 return exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574}
1575
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001576int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1577{
1578 int ret;
1579
1580 cds_ssr_protect(__func__);
1581 ret = __wlan_hdd_cfg80211_resume_wlan(wiphy);
1582 cds_ssr_unprotect(__func__);
1583
1584 return ret;
1585}
1586
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001587static void hdd_suspend_cb(void)
1588{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001589 struct hdd_context *hdd_ctx;
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001590
1591 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1592 if (!hdd_ctx) {
Jeff Johnson6867ec32017-09-29 20:30:20 -07001593 hdd_err("HDD context is NULL");
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001594 return;
1595 }
1596
1597 complete(&hdd_ctx->mc_sus_event_var);
1598}
1599
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001600/**
1601 * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1602 * @wiphy: Pointer to wiphy
1603 * @wow: Pointer to wow
1604 *
1605 * This API is called when cfg80211 driver suspends
1606 *
1607 * Return: integer status
1608 */
1609static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1610 struct cfg80211_wowlan *wow)
1611{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001612 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001614 struct hdd_adapter *adapter;
Jeff Johnson5287de52017-10-28 12:23:06 -07001615 struct hdd_scan_info *scan_info;
Jeff Johnson2954ded2018-06-13 16:34:49 -07001616 mac_handle_t mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001617 int rc;
1618
Dustin Brown491d54b2018-03-14 12:39:11 -07001619 hdd_enter();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001620
Anurag Chouhan6d760662016-02-20 16:05:43 +05301621 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001622 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001623 return -EINVAL;
1624 }
1625
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001626 rc = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301627 if (0 != rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001628 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001629
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001630 mutex_lock(&hdd_ctx->iface_change_lock);
Jianmin Zhu16b94b12018-08-01 09:24:52 +08001631
1632 if (hdd_ctx->driver_status == DRIVER_MODULES_OPENED) {
1633 mutex_unlock(&hdd_ctx->iface_change_lock);
1634 hdd_err("Driver open state, can't suspend");
1635 return -EAGAIN;
1636 }
1637
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001638 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1639 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001640 hdd_debug("Driver Modules not Enabled ");
Arun Khandavallifae92942016-08-01 13:31:08 +05301641 return 0;
1642 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001643 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavallifae92942016-08-01 13:31:08 +05301644
Jeff Johnson2954ded2018-06-13 16:34:49 -07001645 mac_handle = hdd_ctx->mac_handle;
1646
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647 /* If RADAR detection is in progress (HDD), prevent suspend. The flag
1648 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true
1649 * until CAC is done for a SoftAP which is in started state.
1650 */
Dustin Brown920397d2017-12-13 16:27:50 -08001651 hdd_for_each_adapter(hdd_ctx, adapter) {
Dustin Brown63500612018-08-07 11:36:09 -07001652 if (wlan_hdd_validate_session_id(adapter->session_id))
Dustin Brown920397d2017-12-13 16:27:50 -08001653 continue;
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301654
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001655 if (QDF_SAP_MODE == adapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001656 if (BSS_START ==
Jeff Johnson0f9f87b2017-10-28 09:21:06 -07001657 WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter)->bss_state &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001658 true ==
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001659 WLAN_HDD_GET_AP_CTX_PTR(adapter)->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001660 dfs_cac_block_tx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001661 hdd_err("RADAR detection in progress, do not allow suspend");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001662 wlan_hdd_inc_suspend_stats(hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001663 SUSPEND_FAIL_RADAR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001664 return -EAGAIN;
Jeff Johnson60cbd2d2017-11-03 18:26:28 -07001665 } else if (!hdd_ctx->config->enable_sap_suspend) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001666 /* return -EOPNOTSUPP if SAP does not support
1667 * suspend
1668 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001669 hdd_err("SAP does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670 return -EOPNOTSUPP;
1671 }
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001672 } else if (QDF_P2P_GO_MODE == adapter->device_mode) {
Jeff Johnson60cbd2d2017-11-03 18:26:28 -07001673 if (!hdd_ctx->config->enable_sap_suspend) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001674 /* return -EOPNOTSUPP if GO does not support
1675 * suspend
1676 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001677 hdd_err("GO does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001678 return -EOPNOTSUPP;
1679 }
1680 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001681 }
Wu Gao4a1ec8c2018-07-23 19:18:40 +08001682 /* p2p cleanup task based on scheduler */
1683 ucfg_p2p_cleanup_tx_by_psoc(hdd_ctx->hdd_psoc);
1684 ucfg_p2p_cleanup_roc_by_psoc(hdd_ctx->hdd_psoc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001685
1686 /* Stop ongoing scan on each interface */
Dustin Brown920397d2017-12-13 16:27:50 -08001687 hdd_for_each_adapter(hdd_ctx, adapter) {
Jeff Johnson5287de52017-10-28 12:23:06 -07001688 scan_info = &adapter->scan_info;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001689
Jeff Johnson2954ded2018-06-13 16:34:49 -07001690 if (sme_neighbor_middle_of_roaming(mac_handle,
Padma, Santhosh Kumar41552782018-06-29 15:31:25 +05301691 adapter->session_id) ||
1692 hdd_is_roaming_in_progress(hdd_ctx)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001693 hdd_err("Roaming in progress, do not allow suspend");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001694 wlan_hdd_inc_suspend_stats(hdd_ctx,
Dustin Brown105d7902016-10-03 16:27:59 -07001695 SUSPEND_FAIL_ROAM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001696 return -EAGAIN;
1697 }
1698
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001699 wlan_abort_scan(hdd_ctx->hdd_pdev, INVAL_PDEV_ID,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001700 adapter->session_id, INVALID_SCAN_ID, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001701 }
1702
Dustin Brown84411b02017-07-21 16:44:44 -07001703 /* flush any pending powersave timers */
Dustin Brown6619bc22018-07-18 15:04:33 -07001704 hdd_for_each_adapter(hdd_ctx, adapter) {
Dustin Brownbee82832018-07-23 10:10:51 -07001705 if (wlan_hdd_validate_session_id(adapter->session_id))
Dustin Brown6619bc22018-07-18 15:04:33 -07001706 continue;
1707
Jeff Johnson2954ded2018-06-13 16:34:49 -07001708 sme_ps_timer_flush_sync(mac_handle, adapter->session_id);
Dustin Brown6619bc22018-07-18 15:04:33 -07001709 }
Dustin Brown84411b02017-07-21 16:44:44 -07001710
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711 /*
1712 * Suspend IPA early before proceeding to suspend other entities like
1713 * firmware to avoid any race conditions.
1714 */
Sravan Kumar Kairam1309e7e2018-03-13 09:29:52 +05301715 if (ucfg_ipa_suspend(hdd_ctx->hdd_pdev)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001716 hdd_err("IPA not ready to suspend!");
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001717 wlan_hdd_inc_suspend_stats(hdd_ctx, SUSPEND_FAIL_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001718 return -EAGAIN;
1719 }
1720
Rajeev Kumareada0d02016-12-08 17:44:17 -08001721 /* Suspend control path scheduler */
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001722 scheduler_register_hdd_suspend_callback(hdd_suspend_cb);
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301723 scheduler_set_event_mask(MC_SUSPEND_EVENT);
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001724 scheduler_wake_up_controller_thread();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001725
Rajeev Kumareada0d02016-12-08 17:44:17 -08001726 /* Wait for suspend confirmation from scheduler */
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001727 rc = wait_for_completion_timeout(&hdd_ctx->mc_sus_event_var,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001728 msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
1729 if (!rc) {
Manjeet Singh1a376ce2016-10-06 19:31:10 +05301730 scheduler_clear_event_mask(MC_SUSPEND_EVENT);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001731 hdd_err("Failed to stop mc thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732 goto resume_tx;
1733 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001734 hdd_ctx->is_scheduler_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001735
Mohit Khanna70322002018-05-15 19:21:32 -07001736 if (hdd_ctx->enable_rxthread) {
1737 /* Suspend tlshim rx thread */
1738 set_bit(RX_SUSPEND_EVENT, &cds_sched_context->ol_rx_event_flag);
1739 wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue);
1740 rc = wait_for_completion_timeout(&cds_sched_context->
1741 ol_suspend_rx_event,
1742 msecs_to_jiffies
1743 (HDD_RXTHREAD_SUSPEND_TIMEOUT)
1744 );
1745 if (!rc) {
1746 clear_bit(RX_SUSPEND_EVENT,
1747 &cds_sched_context->ol_rx_event_flag);
1748 hdd_err("Failed to stop tl_shim rx thread");
1749 goto resume_all;
1750 }
1751 hdd_ctx->is_ol_rx_thread_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001752 }
Mohit Khanna70322002018-05-15 19:21:32 -07001753
1754 if (hdd_ctx->enable_dp_rx_threads)
1755 dp_txrx_suspend(cds_get_context(QDF_MODULE_ID_SOC));
1756
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301757 if (hdd_suspend_wlan() < 0)
1758 goto resume_all;
1759
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301760 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301761 TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
Jeff Johnson214671b2017-10-30 19:45:23 -07001762 NO_SESSION, hdd_ctx->is_wiphy_suspended));
1763 hdd_ctx->is_wiphy_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001764
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001765 pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_NONE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001766
Dustin Browne74003f2018-03-14 12:51:58 -07001767 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001768 return 0;
1769
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770resume_all:
Rajeev Kumar0b732952016-12-08 17:51:39 -08001771 scheduler_resume();
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001772 hdd_ctx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001773resume_tx:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001774 hdd_resume_wlan();
1775 return -ETIME;
1776
1777}
1778
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001779int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1780 struct cfg80211_wowlan *wow)
1781{
1782 int ret;
1783
1784 cds_ssr_protect(__func__);
1785 ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
1786 cds_ssr_unprotect(__func__);
1787
1788 return ret;
1789}
1790
1791/**
Komal Seelama89be8d2016-09-29 11:09:26 +05301792 * hdd_stop_dhcp_ind() - API to stop DHCP sequence
1793 * @adapter: Adapter on which DHCP needs to be stopped
1794 *
1795 * Release the wakelock held for DHCP process and allow
1796 * the runtime pm to continue
1797 *
1798 * Return: None
1799 */
Jeff Johnson75b737d2017-08-29 14:24:41 -07001800static void hdd_stop_dhcp_ind(struct hdd_adapter *adapter)
Komal Seelama89be8d2016-09-29 11:09:26 +05301801{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001802 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Komal Seelama89be8d2016-09-29 11:09:26 +05301803
Srinivas Girigowdac06543c2017-03-09 15:10:03 -08001804 hdd_debug("DHCP stop indicated through power save");
Jeff Johnson2954ded2018-06-13 16:34:49 -07001805 sme_dhcp_stop_ind(hdd_ctx->mac_handle, adapter->device_mode,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001806 adapter->mac_addr.bytes,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001807 adapter->session_id);
Komal Seelama89be8d2016-09-29 11:09:26 +05301808 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
Jingxiang Geb49aa302018-01-17 20:54:15 +08001809 qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect);
Komal Seelama89be8d2016-09-29 11:09:26 +05301810}
1811
1812/**
1813 * hdd_start_dhcp_ind() - API to start DHCP sequence
1814 * @adapter: Adapter on which DHCP needs to be stopped
1815 *
1816 * Prevent APPS suspend and the runtime suspend during
1817 * DHCP sequence
1818 *
1819 * Return: None
1820 */
Jeff Johnson75b737d2017-08-29 14:24:41 -07001821static void hdd_start_dhcp_ind(struct hdd_adapter *adapter)
Komal Seelama89be8d2016-09-29 11:09:26 +05301822{
Jeff Johnsoncfb65a82017-08-28 11:45:41 -07001823 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Komal Seelama89be8d2016-09-29 11:09:26 +05301824
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001825 hdd_debug("DHCP start indicated through power save");
Jingxiang Geb49aa302018-01-17 20:54:15 +08001826 qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.connect);
Dustin Brownceed67e2017-05-26 11:57:31 -07001827 hdd_prevent_suspend_timeout(HDD_WAKELOCK_TIMEOUT_CONNECT,
1828 WIFI_POWER_EVENT_WAKELOCK_DHCP);
Jeff Johnson2954ded2018-06-13 16:34:49 -07001829 sme_dhcp_start_ind(hdd_ctx->mac_handle, adapter->device_mode,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001830 adapter->mac_addr.bytes,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001831 adapter->session_id);
Komal Seelama89be8d2016-09-29 11:09:26 +05301832}
1833
1834/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001835 * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
1836 * @wiphy: Pointer to wiphy
1837 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07001838 * @allow_power_save: is wlan allowed to go into power save mode
1839 * @timeout: Timeout value in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001840 *
1841 * Return: 0 for success, non-zero for failure
1842 */
1843static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07001844 struct net_device *dev,
1845 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001846 int timeout)
1847{
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001848 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001849 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001850 int status;
1851
Dustin Brown491d54b2018-03-14 12:39:11 -07001852 hdd_enter();
Dustin Brownecfce632016-09-13 10:41:45 -07001853
Dustin Brownf660fb42016-09-09 12:04:00 -07001854 if (timeout < 0) {
Yeshwanth Sriram Guntukaae03c432017-11-12 13:31:02 +05301855 hdd_debug("User space timeout: %d; Enter full power or power save",
1856 timeout);
1857 timeout = 0;
Dustin Brownf660fb42016-09-09 12:04:00 -07001858 }
1859
Anurag Chouhan6d760662016-02-20 16:05:43 +05301860 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001861 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862 return -EINVAL;
1863 }
1864
Dustin Brown63500612018-08-07 11:36:09 -07001865 if (wlan_hdd_validate_session_id(adapter->session_id))
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301866 return -EINVAL;
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301867
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301868 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001869 TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
Jeff Johnson1b780e42017-10-31 14:11:45 -07001870 adapter->session_id, timeout));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001871
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001872 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001873 status = wlan_hdd_validate_context(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001874
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301875 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001876 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001878 mutex_lock(&hdd_ctx->iface_change_lock);
1879 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
1880 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001881 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05301882 return 0;
1883 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001884 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavalli99286452016-08-22 12:13:41 +05301885
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001886 status = wlan_hdd_set_powersave(adapter, allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001887
Jeff Johnsonf6d24282017-10-02 13:25:25 -07001888 allow_power_save ? hdd_stop_dhcp_ind(adapter) :
1889 hdd_start_dhcp_ind(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001890
Dustin Browne74003f2018-03-14 12:51:58 -07001891 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001892 return status;
1893}
1894
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001895int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07001896 struct net_device *dev,
1897 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001898 int timeout)
1899{
1900 int ret;
1901
1902 cds_ssr_protect(__func__);
Dustin Brownf660fb42016-09-09 12:04:00 -07001903 ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev,
1904 allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001905 cds_ssr_unprotect(__func__);
1906
1907 return ret;
1908}
1909
1910/**
1911 * __wlan_hdd_cfg80211_set_txpower() - set TX power
1912 * @wiphy: Pointer to wiphy
1913 * @wdev: Pointer to network device
1914 * @type: TX power setting type
1915 * @dbm: TX power in dbm
1916 *
1917 * Return: 0 for success, non-zero for failure
1918 */
1919static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001920 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001921 enum nl80211_tx_power_setting type,
1922 int dbm)
1923{
Jeff Johnson1a9b9792017-09-03 09:22:08 -07001924 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Jeff Johnson2954ded2018-06-13 16:34:49 -07001925 mac_handle_t mac_handle;
Dustin Brownce5b3d32018-01-17 15:07:38 -08001926 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
1927 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BCAST_INIT;
Jeff Johnson2954ded2018-06-13 16:34:49 -07001928 QDF_STATUS status;
1929 int errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001930
Dustin Brown491d54b2018-03-14 12:39:11 -07001931 hdd_enter();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001932
Anurag Chouhan6d760662016-02-20 16:05:43 +05301933 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001934 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001935 return -EINVAL;
1936 }
1937
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301938 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001939 TRACE_CODE_HDD_CFG80211_SET_TXPOWER,
1940 NO_SESSION, type));
1941
Jeff Johnson2954ded2018-06-13 16:34:49 -07001942 errno = wlan_hdd_validate_context(hdd_ctx);
1943 if (errno)
1944 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001945
Jeff Johnson2954ded2018-06-13 16:34:49 -07001946 mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001947
Jeff Johnson2954ded2018-06-13 16:34:49 -07001948 status = sme_cfg_set_int(mac_handle, WNI_CFG_CURRENT_TX_POWER_LEVEL,
1949 dbm);
1950 if (QDF_IS_STATUS_ERROR(status)) {
1951 hdd_err("sme_cfg_set_int failed for tx power %hu, %d",
1952 dbm, status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001953 return -EIO;
1954 }
1955
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08001956 hdd_debug("Set tx power level %d dbm", dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001957
1958 switch (type) {
1959 /* Automatically determine transmit power */
1960 case NL80211_TX_POWER_AUTOMATIC:
1961 /* Fall through */
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301962 case NL80211_TX_POWER_LIMITED:
1963 /* Limit TX power by the mBm parameter */
Jeff Johnson2954ded2018-06-13 16:34:49 -07001964 status = sme_set_max_tx_power(mac_handle, bssid, selfMac, dbm);
1965 if (QDF_IS_STATUS_ERROR(status)) {
1966 hdd_err("Setting maximum tx power failed, %d", status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001967 return -EIO;
1968 }
1969 break;
1970
1971 case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001972 hdd_err("NL80211_TX_POWER_FIXED not supported");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001973 return -EOPNOTSUPP;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001974
1975 default:
Jeff Johnsonc3273322016-07-06 15:28:17 -07001976 hdd_err("Invalid power setting type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001977 return -EIO;
1978 }
1979
Dustin Browne74003f2018-03-14 12:51:58 -07001980 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001981 return 0;
1982}
1983
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001984int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001985 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001986 enum nl80211_tx_power_setting type,
1987 int dbm)
1988{
1989 int ret;
Ashish Kumar Dhanotiyacf11bae2017-04-04 03:29:47 +05301990
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991 cds_ssr_protect(__func__);
1992 ret = __wlan_hdd_cfg80211_set_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001993 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001994 type, dbm);
1995 cds_ssr_unprotect(__func__);
1996
1997 return ret;
1998}
1999
Naveen Rawate8b1b822018-01-30 09:46:16 -08002000#ifdef QCA_SUPPORT_CP_STATS
2001static void wlan_hdd_get_tx_power(struct hdd_adapter *adapter, int *dbm)
2002{
2003 wlan_cfg80211_mc_cp_stats_get_tx_power(adapter->hdd_vdev, dbm);
2004}
2005#else
2006static void wlan_hdd_get_tx_power(struct hdd_adapter *adapter, int *dbm)
2007{
2008 wlan_hdd_get_class_astats(adapter);
2009 *dbm = adapter->hdd_stats.class_a_stat.max_pwr;
2010}
2011#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002012/**
2013 * __wlan_hdd_cfg80211_get_txpower() - get TX power
2014 * @wiphy: Pointer to wiphy
2015 * @wdev: Pointer to network device
2016 * @dbm: Pointer to TX power in dbm
2017 *
2018 * Return: 0 for success, non-zero for failure
2019 */
2020static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002021 struct wireless_dev *wdev,
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002022 int *dbm)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002023{
2024
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002025 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002026 struct net_device *ndev = wdev->netdev;
Jeff Johnson75b737d2017-08-29 14:24:41 -07002027 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002028 int status;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07002029 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002030
Dustin Brown63500612018-08-07 11:36:09 -07002031 hdd_enter_dev(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002032
Anurag Chouhan6d760662016-02-20 16:05:43 +05302033 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002034 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002035 return -EINVAL;
2036 }
2037
Dustin Brown63500612018-08-07 11:36:09 -07002038 *dbm = 0;
2039
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002040 status = wlan_hdd_validate_context(hdd_ctx);
Dustin Brown63500612018-08-07 11:36:09 -07002041 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043
Arun Khandavalli99286452016-08-22 12:13:41 +05302044 /* Validate adapter sessionId */
Dustin Brown63500612018-08-07 11:36:09 -07002045 status = wlan_hdd_validate_session_id(adapter->session_id);
2046 if (status)
2047 return status;
Arun Khandavalli99286452016-08-22 12:13:41 +05302048
Abhinav Kumar50d4dc72018-06-15 16:35:50 +05302049 if (sta_ctx->hdd_reassoc_scenario) {
2050 hdd_debug("Roaming is in progress, rej this req");
2051 return -EINVAL;
2052 }
2053
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002054 mutex_lock(&hdd_ctx->iface_change_lock);
2055 if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) {
2056 mutex_unlock(&hdd_ctx->iface_change_lock);
Srinivas Girigowda5d6bde62017-03-06 18:26:02 -08002057 hdd_debug("Driver Module not enabled return success");
Arun Khandavalli99286452016-08-22 12:13:41 +05302058 /* Send cached data to upperlayer*/
Jeff Johnson861dd4f2017-10-24 10:10:40 -07002059 *dbm = adapter->hdd_stats.class_a_stat.max_pwr;
Arun Khandavalli99286452016-08-22 12:13:41 +05302060 return 0;
2061 }
Jeff Johnson1a9b9792017-09-03 09:22:08 -07002062 mutex_unlock(&hdd_ctx->iface_change_lock);
Arun Khandavalli99286452016-08-22 12:13:41 +05302063
Ganesh Kondabattinif847f062017-05-26 12:36:24 +05302064 if (sta_ctx->conn_info.connState != eConnectionState_Associated) {
2065 hdd_debug("Not associated");
Ganesh Kondabattinif847f062017-05-26 12:36:24 +05302066 return 0;
2067 }
2068
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302069 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302070 TRACE_CODE_HDD_CFG80211_GET_TXPOWER,
Jeff Johnson1b780e42017-10-31 14:11:45 -07002071 adapter->session_id, adapter->device_mode));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002072
Naveen Rawate8b1b822018-01-30 09:46:16 -08002073 wlan_hdd_get_tx_power(adapter, dbm);
2074 hdd_debug("power: %d", *dbm);
2075
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002076 return 0;
2077}
2078
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002079int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002080 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002081 int *dbm)
2082{
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002083 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084
2085 cds_ssr_protect(__func__);
Srinivas Girigowda5557a392017-03-09 14:28:36 -08002086 ret = __wlan_hdd_cfg80211_get_txpower(wiphy, wdev, dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002087 cds_ssr_unprotect(__func__);
2088
2089 return ret;
2090}
Kapil Gupta6213c012016-09-02 19:39:09 +05302091
Jeff Johnson4fbee2f2017-10-03 11:19:35 -07002092int hdd_set_qpower_config(struct hdd_context *hddctx,
2093 struct hdd_adapter *adapter,
Dustin Brown10a7b712016-10-07 10:31:16 -07002094 u8 qpower)
Kapil Gupta6213c012016-09-02 19:39:09 +05302095{
Dustin Brown10a7b712016-10-07 10:31:16 -07002096 QDF_STATUS status;
Kapil Gupta6213c012016-09-02 19:39:09 +05302097
2098 if (!hddctx->config->enablePowersaveOffload) {
2099 hdd_err("qpower is disabled in configuration");
2100 return -EINVAL;
2101 }
Manjeet Singh91b7bb82017-02-10 18:35:40 +05302102 if (adapter->device_mode != QDF_STA_MODE &&
2103 adapter->device_mode != QDF_P2P_CLIENT_MODE) {
Dustin Brownbacc48f2018-03-14 14:48:44 -07002104 hdd_info("QPOWER only allowed in STA/P2P-Client modes:%d",
2105 adapter->device_mode);
Manjeet Singh91b7bb82017-02-10 18:35:40 +05302106 return -EINVAL;
2107 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002108
Kapil Gupta6213c012016-09-02 19:39:09 +05302109 if (qpower > PS_DUTY_CYCLING_QPOWER ||
2110 qpower < PS_LEGACY_NODEEPSLEEP) {
Dustin Brown10a7b712016-10-07 10:31:16 -07002111 hdd_err("invalid qpower value: %d", qpower);
Kapil Gupta6213c012016-09-02 19:39:09 +05302112 return -EINVAL;
2113 }
Kapil Gupta6213c012016-09-02 19:39:09 +05302114
Kiran Kumar Lokere7006e0a2017-03-07 19:28:36 -08002115 if (hddctx->config->nMaxPsPoll) {
2116 if ((qpower == PS_QPOWER_NODEEPSLEEP) ||
2117 (qpower == PS_LEGACY_NODEEPSLEEP))
2118 qpower = PS_LEGACY_NODEEPSLEEP;
2119 else
2120 qpower = PS_LEGACY_DEEPSLEEP;
2121 hdd_info("Qpower disabled, %d", qpower);
2122 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07002123 status = wma_set_qpower_config(adapter->session_id, qpower);
Dustin Brown10a7b712016-10-07 10:31:16 -07002124 if (status != QDF_STATUS_SUCCESS) {
2125 hdd_err("failed to configure qpower: %d", status);
2126 return -EINVAL;
Kapil Gupta6213c012016-09-02 19:39:09 +05302127 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002128
Kapil Gupta6213c012016-09-02 19:39:09 +05302129 return 0;
2130}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002131
Dustin Brown54096432017-02-23 13:00:44 -08002132
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002133#ifdef WLAN_SUSPEND_RESUME_TEST
Dustin Brownbc81a472016-10-26 16:56:59 -07002134static struct net_device *g_dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002135static struct wiphy *g_wiphy;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002136static enum wow_resume_trigger g_resume_trigger;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002137
2138#define HDD_FA_SUSPENDED_BIT (0)
2139static unsigned long fake_apps_state;
2140
Dustin Brownd53d1a82016-10-03 12:57:33 -07002141/**
2142 * __hdd_wlan_fake_apps_resume() - The core logic for
2143 * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(),
2144 * which is only need for non-irq resume
Dustin Brownbc81a472016-10-26 16:56:59 -07002145 * @wiphy: the kernel wiphy struct for the device being resumed
2146 * @dev: the kernel net_device struct for the device being resumed
Dustin Brownd53d1a82016-10-03 12:57:33 -07002147 *
Dustin Brownbc81a472016-10-26 16:56:59 -07002148 * Return: none, calls QDF_BUG() on failure
Dustin Brownd53d1a82016-10-03 12:57:33 -07002149 */
Dustin Brownbc81a472016-10-26 16:56:59 -07002150static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy,
2151 struct net_device *dev)
Dustin Brownd53d1a82016-10-03 12:57:33 -07002152{
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002153 struct hif_opaque_softc *hif_ctx;
Dustin Brownddb59702017-01-12 16:20:31 -08002154 qdf_device_t qdf_dev;
Dustin Brownd53d1a82016-10-03 12:57:33 -07002155
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002156 hdd_info("Unit-test resume WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002157
2158 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2159 if (!qdf_dev) {
2160 hdd_err("Failed to get QDF device context");
2161 QDF_BUG(0);
2162 return;
2163 }
2164
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002165 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2166 if (!hif_ctx) {
2167 hdd_err("Failed to get HIF context");
2168 return;
2169 }
2170
Dustin Brownd53d1a82016-10-03 12:57:33 -07002171 if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002172 hdd_alert("Not unit-test suspended; Nothing to do");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002173 return;
2174 }
2175
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002176 /* simulate kernel disable irqs */
2177 QDF_BUG(!hif_apps_wake_irq_disable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002178
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002179 QDF_BUG(!wlan_hdd_bus_resume_noirq());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002180
2181 /* simulate kernel enable irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002182 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
Dustin Brownd53d1a82016-10-03 12:57:33 -07002183
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002184 QDF_BUG(!wlan_hdd_bus_resume());
Dustin Brownd53d1a82016-10-03 12:57:33 -07002185
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002186 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
2187
2188 if (g_resume_trigger == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2189 hif_vote_link_down(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002190
2191 dev->watchdog_timeo = HDD_TX_TIMEOUT;
Dustin Brown562b9672016-12-22 15:25:33 -08002192
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002193 hdd_alert("Unit-test resume succeeded");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002194}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002195
2196/**
2197 * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming
2198 * from unit-test initiated suspend from irq wakeup signal
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002199 *
2200 * Resume wlan after getting very 1st CE interrupt from target
2201 *
2202 * Return: none
2203 */
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002204static void hdd_wlan_fake_apps_resume_irq_callback(void)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002205{
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002206 hdd_info("Trigger unit-test resume WLAN");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002207
2208 QDF_BUG(g_wiphy);
Dustin Brownbc81a472016-10-26 16:56:59 -07002209 QDF_BUG(g_dev);
2210 __hdd_wlan_fake_apps_resume(g_wiphy, g_dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002211 g_wiphy = NULL;
Dustin Brownbc81a472016-10-26 16:56:59 -07002212 g_dev = NULL;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002213}
2214
Dustin Brown54096432017-02-23 13:00:44 -08002215int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev,
2216 enum wow_interface_pause pause_setting,
2217 enum wow_resume_trigger resume_setting)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002218{
Rajeev Kumar15b40a22018-04-12 11:45:24 -07002219 int errno;
Dustin Brownddb59702017-01-12 16:20:31 -08002220 qdf_device_t qdf_dev;
2221 struct hif_opaque_softc *hif_ctx;
Rajeev Kumar15b40a22018-04-12 11:45:24 -07002222 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
Dustin Brown54096432017-02-23 13:00:44 -08002223 struct wow_enable_params wow_params = {
2224 .is_unit_test = true,
2225 .interface_pause = pause_setting,
2226 .resume_trigger = resume_setting
2227 };
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002228
Rajeev Kumar15b40a22018-04-12 11:45:24 -07002229 if (wlan_hdd_validate_context(hdd_ctx))
2230 return -EINVAL;
2231
2232 if (!hdd_ctx->config->is_unit_test_framework_enabled) {
2233 hdd_warn_rl("UT framework is disabled");
2234 return -EINVAL;
2235 }
2236
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002237 hdd_info("Unit-test suspend WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002238
Dustin Brown54096432017-02-23 13:00:44 -08002239 if (pause_setting < WOW_INTERFACE_PAUSE_DEFAULT ||
2240 pause_setting >= WOW_INTERFACE_PAUSE_COUNT) {
2241 hdd_err("Invalid interface pause %d (expected range [0, 2])",
2242 pause_setting);
2243 return -EINVAL;
2244 }
2245
2246 if (resume_setting < WOW_RESUME_TRIGGER_DEFAULT ||
2247 resume_setting >= WOW_RESUME_TRIGGER_COUNT) {
2248 hdd_err("Invalid resume trigger %d (expected range [0, 2])",
2249 resume_setting);
2250 return -EINVAL;
2251 }
2252
Dustin Brownddb59702017-01-12 16:20:31 -08002253 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2254 if (!qdf_dev) {
2255 hdd_err("Failed to get QDF device context");
2256 return -EINVAL;
2257 }
2258
2259 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2260 if (!hif_ctx) {
2261 hdd_err("Failed to get HIF context");
2262 return -EINVAL;
2263 }
2264
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002265 if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002266 hdd_alert("Already unit-test suspended; Nothing to do");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002267 return 0;
2268 }
2269
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002270 /* pci link is needed to wakeup from HTC wakeup trigger */
2271 if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP)
2272 hif_vote_link_up(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002273
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002274 errno = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL);
2275 if (errno)
2276 goto link_down;
2277
2278 errno = wlan_hdd_unit_test_bus_suspend(wow_params);
2279 if (errno)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002280 goto cfg80211_resume;
2281
2282 /* simulate kernel disabling irqs */
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002283 errno = hif_apps_irqs_disable(hif_ctx);
2284 if (errno)
2285 goto bus_resume;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002286
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002287 errno = wlan_hdd_bus_suspend_noirq();
2288 if (errno)
2289 goto enable_irqs;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002290
Dustin Brownbc81a472016-10-26 16:56:59 -07002291 /* pass wiphy/dev to callback via global variables */
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002292 g_wiphy = wiphy;
Dustin Brownbc81a472016-10-26 16:56:59 -07002293 g_dev = dev;
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002294 g_resume_trigger = resume_setting;
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002295 hif_ut_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002296
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002297 /* re-enable wake irq */
2298 errno = hif_apps_wake_irq_enable(hif_ctx);
2299 if (errno)
2300 goto fake_apps_resume;
2301
Dustin Brownbc81a472016-10-26 16:56:59 -07002302 /*
2303 * Tell the kernel not to worry if TX queues aren't moving. This is
2304 * expected since we are suspending the wifi hardware, but not APPS
2305 */
2306 dev->watchdog_timeo = INT_MAX;
2307
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002308 hdd_alert("Unit-test suspend succeeded");
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002309
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002310 return 0;
2311
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002312fake_apps_resume:
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002313 hif_ut_apps_resume(hif_ctx);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002314
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002315enable_irqs:
2316 QDF_BUG(!hif_apps_irqs_enable(hif_ctx));
2317
2318bus_resume:
2319 QDF_BUG(!wlan_hdd_bus_resume());
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002320
2321cfg80211_resume:
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002322 QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy));
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002323
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002324link_down:
2325 hif_vote_link_down(hif_ctx);
2326
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002327 clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state);
Dustin Brown3ed3e9b2017-03-23 12:57:58 -07002328 hdd_err("Unit-test suspend failed: %d", errno);
2329
2330 return errno;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002331}
2332
Dustin Brownbc81a472016-10-26 16:56:59 -07002333int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002334{
Dustin Brownddb59702017-01-12 16:20:31 -08002335 struct hif_opaque_softc *hif_ctx;
Rajeev Kumar15b40a22018-04-12 11:45:24 -07002336 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
2337
2338 if (wlan_hdd_validate_context(hdd_ctx))
2339 return -EINVAL;
2340
2341 if (!hdd_ctx->config->is_unit_test_framework_enabled) {
2342 hdd_warn_rl("UT framework is disabled");
2343 return -EINVAL;
2344 }
Dustin Brownddb59702017-01-12 16:20:31 -08002345
2346 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2347 if (!hif_ctx) {
2348 hdd_err("Failed to get HIF context");
2349 return -EINVAL;
2350 }
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002351
Dustin Brown0f8dc3d2017-06-01 14:37:26 -07002352 hif_ut_apps_resume(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002353 __hdd_wlan_fake_apps_resume(wiphy, dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002354
2355 return 0;
2356}
2357#endif