blob: 4be1736cf6208901ad4deb4ed937c3f0e48e73fe [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Poddar, Siddartha78cac32016-12-29 20:08:34 +05302 * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_power.c
30 *
31 * WLAN power management functions
32 *
33 */
34
35/* Include files */
36
37#include <linux/pm.h>
38#include <linux/wait.h>
39#include <linux/cpu.h>
40#include <wlan_hdd_includes.h>
41#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK)
42#include <linux/wakelock.h>
43#endif
Anurag Chouhan6d760662016-02-20 16:05:43 +053044#include "qdf_types.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080045#include "sme_api.h"
46#include <cds_api.h>
47#include <cds_sched.h>
48#include <mac_init_api.h>
49#include <wlan_qct_sys.h>
50#include <wlan_hdd_main.h>
51#include <wlan_hdd_assoc.h>
52#include <wlan_nlink_srv.h>
53#include <wlan_hdd_misc.h>
54#include <wlan_hdd_power.h>
Jeff Johnsonc8d0c252016-10-05 16:19:50 -070055#include <wlan_hdd_host_offload.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080056#include <dbglog_host.h>
57#include <wlan_hdd_trace.h>
Masti, Narayanraddi3e26de62016-08-19 14:33:22 +053058#include <wlan_hdd_p2p.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080059
60#include <linux/semaphore.h>
61#include <wlan_hdd_hostapd.h>
62#include "cfg_api.h"
63
64#include <linux/inetdevice.h>
65#include <wlan_hdd_cfg.h>
Sandeep Puligillae390be52016-02-08 17:07:05 -080066#include <wlan_hdd_scan.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080067#include <wlan_hdd_cfg80211.h>
68#include <net/addrconf.h>
69#include <wlan_hdd_ipa.h>
Jeff Johnson2b0a7b82016-05-18 15:08:02 -070070#include <wlan_hdd_lpass.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071
72#include <wma_types.h>
Poddar, Siddartha78cac32016-12-29 20:08:34 +053073#include <ol_txrx_osif_api.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080074#include "hif.h"
75#include "sme_power_save_api.h"
Chandrasekaran, Manishekar0d814c72015-11-05 10:42:48 +053076#include "cds_concurrency.h"
Dhanashri Atreb08959a2016-03-01 17:28:03 -080077#include "cdp_txrx_flow_ctrl_v2.h"
Yuanyuan Liu13738502016-04-06 17:41:37 -070078#include "pld_common.h"
Rajeev Kumar9bb2e852016-09-24 12:29:25 -070079#include "wlan_hdd_driver_ops.h"
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +053080#include <wlan_logging_sock_svc.h>
Krunal Sonid32c6bc2016-10-18 18:00:21 -070081#include "scheduler_api.h"
yeshwanth sriram guntuka310b3ac2016-11-15 23:25:26 +053082#include "cds_utils.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080083
84/* Preprocessor definitions and constants */
Yue Ma4ea4f052015-10-27 12:25:27 -070085#define HDD_SSR_BRING_UP_TIME 30000
Sreelakshmi Konamki22528532016-09-06 16:34:50 +053086#define HDD_WAKE_LOCK_RESUME_DURATION 1000
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080087
88/* Type declarations */
89
Abhishek Singhbaea27d2016-04-27 13:29:30 +053090#ifdef FEATURE_WLAN_DIAG_SUPPORT
91/**
92 * hdd_wlan_suspend_resume_event()- send suspend/resume state
93 * @state: suspend/resume state
94 *
95 * This Function send send suspend resume state diag event
96 *
97 * Return: void.
98 */
99void hdd_wlan_suspend_resume_event(uint8_t state)
100{
101 WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend);
102 qdf_mem_zero(&suspend_state, sizeof(suspend_state));
103
104 suspend_state.state = state;
105 WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
106}
Abhishek Singh4aad0f72016-04-27 13:43:29 +0530107
108/**
109 * hdd_wlan_offload_event()- send offloads event
110 * @type: offload type
111 * @state: enabled or disabled
112 *
113 * This Function send offloads enable/disable diag event
114 *
115 * Return: void.
116 */
117
118void hdd_wlan_offload_event(uint8_t type, uint8_t state)
119{
120 WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req);
121 qdf_mem_zero(&host_offload, sizeof(host_offload));
122
123 host_offload.offload_type = type;
124 host_offload.state = state;
125
126 WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ);
127}
Abhishek Singhbaea27d2016-04-27 13:29:30 +0530128#endif
129
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800130/* Function and variables declarations */
131
132extern struct notifier_block hdd_netdev_notifier;
133
134static struct timer_list ssr_timer;
135static bool ssr_timer_started;
Mukul Sharma3d36c392017-01-18 18:39:12 +0530136
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800137/**
Mukul Sharma3d36c392017-01-18 18:39:12 +0530138 * hdd_enable_gtk_offload() - enable GTK offload
139 * @adapter: pointer to the adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140 *
Mukul Sharma3d36c392017-01-18 18:39:12 +0530141 * Central function to enable GTK offload.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800142 *
143 * Return: nothing
144 */
Mukul Sharma3d36c392017-01-18 18:39:12 +0530145static void hdd_enable_gtk_offload(hdd_adapter_t *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800146{
Mukul Sharma3d36c392017-01-18 18:39:12 +0530147 QDF_STATUS status;
148 status = pmo_ucfg_enable_gtk_offload_in_fwr(adapter->hdd_vdev);
149 if (status != QDF_STATUS_SUCCESS)
150 hdd_info("Failed to enable gtk offload");
151}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800152
Mukul Sharma3d36c392017-01-18 18:39:12 +0530153/**
154 * hdd_disable_gtk_offload() - disable GTK offload
155 * @pAdapter: pointer to the adapter
156 *
157 * Central function to disable GTK offload.
158 *
159 * Return: nothing
160 */
161static void hdd_disable_gtk_offload(hdd_adapter_t *adapter)
162{
163 struct pmo_gtk_rsp_req gtk_rsp_request;
164 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165
Mukul Sharma3d36c392017-01-18 18:39:12 +0530166 /* ensure to get gtk rsp first before disable it*/
167 gtk_rsp_request.callback =
168 wlan_hdd_cfg80211_update_replay_counter_callback;
169 /* Passing as void* as PMO does not know legacy HDD adapter type */
170 gtk_rsp_request.callback_context =
171 (void *)adapter;
172 status = pmo_ucfg_get_gtk_rsp(adapter->hdd_vdev,
173 &gtk_rsp_request);
174 if (status != QDF_STATUS_SUCCESS) {
175 hdd_err("Failed to send get gtk rsp status:%d", status);
176 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800177 }
Mukul Sharma3d36c392017-01-18 18:39:12 +0530178 hdd_notice("send get_gtk_rsp successful");
179 status = pmo_ucfg_disable_gtk_offload_in_fwr(adapter->hdd_vdev);
180 if (status != QDF_STATUS_SUCCESS)
181 hdd_info("Failed to disable gtk offload");
182
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800183}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530185
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800186/**
187 * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function
188 * @nb: notifier block that was registered with the kernel
189 * @data: (unused) generic data that was registered with the kernel
190 * @arg: (unused) generic argument that was registered with the kernel
191 *
192 * This is a callback function that is registered with the kernel via
193 * register_inet6addr_notifier() which allows the driver to be
194 * notified when there is an IPv6 address change.
195 *
196 * Return: NOTIFY_DONE to indicate we don't care what happens with
197 * other callbacks
198 */
199static int __wlan_hdd_ipv6_changed(struct notifier_block *nb,
200 unsigned long data, void *arg)
201{
202 struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
203 struct net_device *ndev = ifa->idev->dev;
204 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
205 hdd_context_t *pHddCtx;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700206 hdd_station_ctx_t *sta_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207 int status;
208
Jeff Johnson158c8d02016-10-31 13:11:48 -0700209 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530210
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211 if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700212 hdd_err("Adapter context is invalid %p", pAdapter);
Jeff Johnson158c8d02016-10-31 13:11:48 -0700213 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800214 }
215
216 if ((pAdapter->dev == ndev) &&
Jeff Johnson158c8d02016-10-31 13:11:48 -0700217 (pAdapter->device_mode == QDF_STA_MODE ||
218 pAdapter->device_mode == QDF_P2P_CLIENT_MODE ||
219 pAdapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800220 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
221 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530222 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800223 return NOTIFY_DONE;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700224 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Abhishek Singhca408032016-09-13 15:26:12 +0530225 if (eConnectionState_Associated ==
Jeff Johnson158c8d02016-10-31 13:11:48 -0700226 sta_ctx->conn_info.connState) {
227 hdd_info("invoking sme_dhcp_done_ind");
Abhishek Singhca408032016-09-13 15:26:12 +0530228 sme_dhcp_done_ind(pHddCtx->hHal,
Jeff Johnson158c8d02016-10-31 13:11:48 -0700229 pAdapter->sessionId);
230 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800231 schedule_work(&pAdapter->ipv6NotifierWorkQueue);
232 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530233 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800234 return NOTIFY_DONE;
235}
236
237/**
238 * wlan_hdd_ipv6_changed() - IPv6 change notifier callback
239 * @nb: pointer to notifier block
240 * @data: data
241 * @arg: arg
242 *
243 * This is the IPv6 notifier callback function gets invoked
244 * if any change in IP and then invoke the function @__wlan_hdd_ipv6_changed
245 * to reconfigure the offload parameters.
246 *
247 * Return: 0 on success, error number otherwise.
248 */
249int wlan_hdd_ipv6_changed(struct notifier_block *nb,
250 unsigned long data, void *arg)
251{
252 int ret;
253
254 cds_ssr_protect(__func__);
255 ret = __wlan_hdd_ipv6_changed(nb, data, arg);
256 cds_ssr_unprotect(__func__);
257
258 return ret;
259}
260
261/**
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530262 * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses
263 * @idev: pointer to net device
264 * @ipv6addr: destination array to fill IPv6 addresses
265 * @ipv6addr_type: IPv6 Address type
266 * @count: number of IPv6 addresses
267 *
268 * This is the IPv6 utility function to populate unicast addresses.
269 *
270 * Return: 0 on success, error number otherwise.
271 */
272static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev,
273 uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN],
274 uint8_t *ipv6addr_type, uint32_t *count)
275{
276 struct inet6_ifaddr *ifa;
277 struct list_head *p;
278 uint32_t scope;
279
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700280 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530281 list_for_each(p, &idev->addr_list) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530282 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700283 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530284 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700285 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530286 ifa = list_entry(p, struct inet6_ifaddr, if_list);
287 if (ifa->flags & IFA_F_DADFAILED)
288 continue;
289 scope = ipv6_addr_src_scope(&ifa->addr);
290 switch (scope) {
291 case IPV6_ADDR_SCOPE_GLOBAL:
292 case IPV6_ADDR_SCOPE_LINKLOCAL:
293 qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr,
294 sizeof(ifa->addr.s6_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530295 ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE;
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530296 hdd_info("Index %d scope = %s UC-Address: %pI6",
297 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
298 "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]);
299 *count += 1;
300 break;
301 default:
302 hdd_err("The Scope %d is not supported", scope);
303 }
304 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700305
306 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530307 return 0;
308}
309
310/**
311 * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses
312 * @idev: pointer to net device
313 * @ipv6addr: destination array to fill IPv6 addresses
314 * @ipv6addr_type: IPv6 Address type
315 * @count: number of IPv6 addresses
316 *
317 * This is the IPv6 utility function to populate anycast addresses.
318 *
319 * Return: 0 on success, error number otherwise.
320 */
321static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev,
322 uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN],
323 uint8_t *ipv6addr_type, uint32_t *count)
324{
325 struct ifacaddr6 *ifaca;
326 uint32_t scope;
327
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700328 read_lock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530329 for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530330 if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700331 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530332 return -EINVAL;
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700333 }
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530334 /* For anycast addr no DAD */
335 scope = ipv6_addr_src_scope(&ifaca->aca_addr);
336 switch (scope) {
337 case IPV6_ADDR_SCOPE_GLOBAL:
338 case IPV6_ADDR_SCOPE_LINKLOCAL:
339 qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr,
340 sizeof(ifaca->aca_addr));
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530341 ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE;
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530342 hdd_info("Index %d scope = %s AC-Address: %pI6",
343 *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ?
344 "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]);
345 *count += 1;
346 break;
347 default:
348 hdd_err("The Scope %d is not supported", scope);
349 }
350 }
Srinivas Girigowda90cdd3c2016-10-18 11:28:10 -0700351
352 read_unlock_bh(&idev->lock);
Sravan Kumar Kairamc0873582016-07-26 17:34:57 +0530353 return 0;
354}
355
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530356void hdd_enable_ns_offload(hdd_adapter_t *adapter,
357 enum pmo_offload_trigger trigger)
Dustin Brown2444ee62016-09-06 17:20:36 -0700358{
359 struct inet6_dev *in6_dev;
Dustin Brown2444ee62016-09-06 17:20:36 -0700360 QDF_STATUS status;
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530361 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
362 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
363 struct pmo_ns_req *ns_req = NULL;
364 int err;
365
366 ENTER();
367 if (!psoc) {
368 hdd_err("psoc is NULL");
369 goto out;
370 }
Dustin Brown2444ee62016-09-06 17:20:36 -0700371
372 in6_dev = __in6_dev_get(adapter->dev);
373 if (NULL == in6_dev) {
374 hdd_err("IPv6 dev does not exist. Failed to request NSOffload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530375 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700376 }
377
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530378 ns_req = qdf_mem_malloc(sizeof(*ns_req));
379 if (!ns_req) {
380 hdd_err("fail to allocate ns_req");
381 goto out;
382 }
383
384 ns_req->psoc = psoc;
385 ns_req->vdev_id = adapter->sessionId;
386 ns_req->trigger = trigger;
387 ns_req->count = 0;
388
Dustin Brown2444ee62016-09-06 17:20:36 -0700389 /* Unicast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530390 err = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
391 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700392 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530393 hdd_disable_ns_offload(adapter, trigger);
Dustin Brown2444ee62016-09-06 17:20:36 -0700394 hdd_notice("Reached max supported addresses and not enabling "
395 "NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530396 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700397 }
398
399 /* Anycast Addresses */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530400 err = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
401 ns_req->ipv6_addr_type, &ns_req->count);
Dustin Brown2444ee62016-09-06 17:20:36 -0700402 if (err) {
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530403 hdd_disable_ns_offload(adapter, trigger);
Dustin Brown2444ee62016-09-06 17:20:36 -0700404 hdd_notice("Reached max supported addresses and not enabling "
405 "NS offload");
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530406 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700407 }
408
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530409 /* cache ns request */
410 status = pmo_ucfg_cache_ns_offload_req(ns_req);
411 if (status != QDF_STATUS_SUCCESS) {
412 hdd_err("Failed to cache ns request status: %d", status);
413 goto out;
Dustin Brown2444ee62016-09-06 17:20:36 -0700414 }
415
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530416 /* enable ns request */
417 status = pmo_ucfg_enable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
418 if (status != QDF_STATUS_SUCCESS)
Dustin Brown2444ee62016-09-06 17:20:36 -0700419 hdd_err("Failed to enable HostOffload feature with status: %d",
420 status);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530421 else
422 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE);
423out:
424 if (ns_req)
425 qdf_mem_free(ns_req);
426 EXIT();
427
Dustin Brown2444ee62016-09-06 17:20:36 -0700428}
429
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530430void hdd_disable_ns_offload(hdd_adapter_t *adapter,
431 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800432{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530433 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800434
435 ENTER();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530436 status = pmo_ucfg_flush_ns_offload_req(adapter->hdd_vdev);
437 if (status != QDF_STATUS_SUCCESS) {
438 hdd_err("Failed to flush NS Offload");
439 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800440 }
441
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530442 status = pmo_ucfg_disable_ns_offload_in_fwr(adapter->hdd_vdev, trigger);
443 if (status != QDF_STATUS_SUCCESS)
444 hdd_err("Failed to disable NS Offload");
Dustin Brown2444ee62016-09-06 17:20:36 -0700445 else
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530446 hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD,
447 SIR_OFFLOAD_DISABLE);
448out:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800449 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530450
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800451}
452
453/**
454 * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function
455 * @work: registered work item
456 *
457 * This function performs the work initially trigged by a callback
458 * from the IPv6 netdev notifier. Since this means there has been a
459 * change in IPv6 state for the interface, the NS offload is
460 * reconfigured.
461 *
462 * Return: None
463 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700464static void __hdd_ipv6_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800465{
466 hdd_adapter_t *pAdapter =
467 container_of(work, hdd_adapter_t, ipv6NotifierWorkQueue);
468 hdd_context_t *pHddCtx;
469 int status;
470
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530471 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800472
473 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
474 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530475 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800476 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800477
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530478 hdd_enable_ns_offload(pAdapter, pmo_ipv6_change_notify);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530479 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800480}
481
482/**
483 * hdd_ipv6_notifier_work_queue() - IP V6 change notifier work handler
484 * @work: Pointer to work context
485 *
486 * Return: none
487 */
488void hdd_ipv6_notifier_work_queue(struct work_struct *work)
489{
490 cds_ssr_protect(__func__);
491 __hdd_ipv6_notifier_work_queue(work);
492 cds_ssr_unprotect(__func__);
493}
494
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530495void hdd_enable_host_offloads(hdd_adapter_t *adapter,
496 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800497{
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530498 ENTER();
499
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530500 if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
501 hdd_info("offload is not supported on this vdev opmode: %d",
502 adapter->device_mode);
503 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800504 }
505
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530506 if (!pmo_ucfg_is_vdev_connected(adapter->hdd_vdev)) {
507 hdd_info("vdev is not connected");
508 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800509 }
510
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530511 hdd_info("enable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530512 hdd_enable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530513 hdd_enable_arp_offload(adapter, trigger);
514 hdd_enable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530515 hdd_enable_mc_addr_filtering(adapter, trigger);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530516out:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530517 EXIT();
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530518
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800519}
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530520
521void hdd_disable_host_offloads(hdd_adapter_t *adapter,
522 enum pmo_offload_trigger trigger)
523{
524 ENTER();
525
526 if (!pmo_ucfg_is_vdev_supports_offload(adapter->hdd_vdev)) {
527 hdd_info("offload is not supported on this vdev opmode: %d",
528 adapter->device_mode);
529 goto out;
530 }
531
532 if (!pmo_ucfg_is_vdev_connected(adapter->hdd_vdev)) {
533 hdd_info("vdev is not connected");
534 goto out;
535 }
536
537 hdd_info("disable offloads");
Mukul Sharma3d36c392017-01-18 18:39:12 +0530538 hdd_disable_gtk_offload(adapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530539 hdd_disable_arp_offload(adapter, trigger);
540 hdd_disable_ns_offload(adapter, trigger);
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530541 hdd_disable_mc_addr_filtering(adapter, trigger);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530542out:
543 EXIT();
544
545}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800546
547/**
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800548 * hdd_lookup_ifaddr() - Lookup interface address data by name
549 * @adapter: the adapter whose name should be searched for
550 *
551 * return in_ifaddr pointer on success, NULL for failure
552 */
553static struct in_ifaddr *hdd_lookup_ifaddr(hdd_adapter_t *adapter)
554{
555 struct in_ifaddr *ifa;
556 struct in_device *in_dev;
557
558 if (!adapter) {
559 hdd_err("adapter is null");
560 return NULL;
561 }
562
563 in_dev = __in_dev_get_rtnl(adapter->dev);
564 if (!in_dev) {
565 hdd_err("Failed to get in_device");
566 return NULL;
567 }
568
569 /* lookup address data by interface name */
570 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
571 if (!strcmp(adapter->dev->name, ifa->ifa_label))
572 return ifa;
573 }
574
575 return NULL;
576}
577
578/**
579 * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address
580 * @adapter: the adapter whose IPv4 address is desired
581 * @ipv4_addr: the address of the array to copy the IPv4 address into
582 *
583 * return: zero for success; non-zero for failure
584 */
585static int hdd_populate_ipv4_addr(hdd_adapter_t *adapter, uint8_t *ipv4_addr)
586{
587 struct in_ifaddr *ifa;
588 int i;
589
590 if (!adapter) {
591 hdd_err("adapter is null");
592 return -EINVAL;
593 }
594
595 if (!ipv4_addr) {
596 hdd_err("ipv4_addr is null");
597 return -EINVAL;
598 }
599
600 ifa = hdd_lookup_ifaddr(adapter);
601 if (!ifa || !ifa->ifa_local) {
602 hdd_err("ipv4 address not found");
603 return -EINVAL;
604 }
605
606 /* convert u32 to byte array */
607 for (i = 0; i < 4; i++)
608 ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff;
609
610 return 0;
611}
612
613/**
614 * hdd_set_grat_arp_keepalive() - Enable grat APR keepalive
615 * @adapter: the HDD adapter to configure
616 *
617 * This configures gratuitous APR keepalive based on the adapter's current
618 * connection information, specifically IPv4 address and BSSID
619 *
620 * return: zero for success, non-zero for failure
621 */
622static int hdd_set_grat_arp_keepalive(hdd_adapter_t *adapter)
623{
624 QDF_STATUS status;
625 int exit_code;
626 hdd_context_t *hdd_ctx;
627 hdd_station_ctx_t *sta_ctx;
628 tSirKeepAliveReq req = {
629 .packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP,
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800630 .dest_macaddr = QDF_MAC_ADDR_BROADCAST_INITIALIZER,
631 };
632
633 if (!adapter) {
634 hdd_err("adapter is null");
635 return -EINVAL;
636 }
637
638 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
639 if (!hdd_ctx) {
640 hdd_err("hdd_ctx is null");
641 return -EINVAL;
642 }
643
644 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
645 if (!sta_ctx) {
646 hdd_err("sta_ctx is null");
647 return -EINVAL;
648 }
649
650 exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr);
651 if (exit_code) {
652 hdd_err("Failed to populate ipv4 address");
653 return exit_code;
654 }
655
Dustin Brown6b4643d2017-02-09 12:19:28 -0800656 /* according to RFC5227, sender/target ip address should be the same */
657 qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr,
658 sizeof(req.destIpv4Addr));
659
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800660 qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssId);
661 req.timePeriod = hdd_ctx->config->infraStaKeepAlivePeriod;
662 req.sessionId = adapter->sessionId;
663
664 hdd_info("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u",
665 req.hostIpv4Addr[0], req.hostIpv4Addr[1],
666 req.hostIpv4Addr[2], req.hostIpv4Addr[3]);
667
668 status = sme_set_keep_alive(hdd_ctx->hHal, req.sessionId, &req);
669 if (QDF_IS_STATUS_ERROR(status)) {
670 hdd_err("Failed to set keepalive");
671 return qdf_status_to_os_return(status);
672 }
673
674 return 0;
675}
676
677/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800678 * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function
679 * @work: registered work item
680 *
681 * This function performs the work initially trigged by a callback
682 * from the IPv4 netdev notifier. Since this means there has been a
683 * change in IPv4 state for the interface, the ARP offload is
684 * reconfigured.
685 *
686 * Return: None
687 */
Jeff Johnsonc8d0c252016-10-05 16:19:50 -0700688static void __hdd_ipv4_notifier_work_queue(struct work_struct *work)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800689{
690 hdd_adapter_t *pAdapter =
691 container_of(work, hdd_adapter_t, ipv4NotifierWorkQueue);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530692 ENTER();
693 hdd_enable_arp_offload(pAdapter, pmo_ipv4_change_notify);
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800694 hdd_set_grat_arp_keepalive(pAdapter);
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530695 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800696}
697
698/**
699 * hdd_ipv4_notifier_work_queue() - IP V4 change notifier work handler
700 * @work: Pointer to work context
701 *
702 * Return: none
703 */
704void hdd_ipv4_notifier_work_queue(struct work_struct *work)
705{
706 cds_ssr_protect(__func__);
707 __hdd_ipv4_notifier_work_queue(work);
708 cds_ssr_unprotect(__func__);
709}
710
711/**
712 * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function
713 * @nb: notifier block that was registered with the kernel
714 * @data: (unused) generic data that was registered with the kernel
715 * @arg: (unused) generic argument that was registered with the kernel
716 *
717 * This is a callback function that is registered with the kernel via
718 * register_inetaddr_notifier() which allows the driver to be
719 * notified when there is an IPv4 address change.
720 *
721 * Return: NOTIFY_DONE to indicate we don't care what happens with
722 * other callbacks
723 */
724static int __wlan_hdd_ipv4_changed(struct notifier_block *nb,
725 unsigned long data, void *arg)
726{
727 struct in_ifaddr *ifa = (struct in_ifaddr *)arg;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800728 struct net_device *ndev = ifa->ifa_dev->dev;
729 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
730 hdd_context_t *pHddCtx;
Jeff Johnson158c8d02016-10-31 13:11:48 -0700731 hdd_station_ctx_t *sta_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732 int status;
733
Jeff Johnson158c8d02016-10-31 13:11:48 -0700734 ENTER_DEV(ndev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530735
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800736 if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700737 hdd_err("Adapter context is invalid %p", pAdapter);
Jeff Johnson158c8d02016-10-31 13:11:48 -0700738 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800739 }
740
Jeff Johnson158c8d02016-10-31 13:11:48 -0700741 if ((pAdapter->dev == ndev) &&
742 (pAdapter->device_mode == QDF_STA_MODE ||
743 pAdapter->device_mode == QDF_P2P_CLIENT_MODE ||
744 pAdapter->device_mode == QDF_NDI_MODE)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800745
746 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
747 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530748 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800749 return NOTIFY_DONE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800750
Jeff Johnson158c8d02016-10-31 13:11:48 -0700751 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Abhishek Singhca408032016-09-13 15:26:12 +0530752 if (eConnectionState_Associated ==
Jeff Johnson158c8d02016-10-31 13:11:48 -0700753 sta_ctx->conn_info.connState) {
754 hdd_info("invoking sme_dhcp_done_ind");
Abhishek Singhca408032016-09-13 15:26:12 +0530755 sme_dhcp_done_ind(pHddCtx->hHal,
Jeff Johnson158c8d02016-10-31 13:11:48 -0700756 pAdapter->sessionId);
757 }
Abhishek Singhca408032016-09-13 15:26:12 +0530758
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800759 if (!pHddCtx->config->fhostArpOffload) {
Jeff Johnsonc3273322016-07-06 15:28:17 -0700760 hdd_notice("Offload not enabled ARPOffload=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800761 pHddCtx->config->fhostArpOffload);
762 return NOTIFY_DONE;
763 }
764
Dustin Brown3c31ceb2017-02-01 14:43:52 -0800765 ifa = hdd_lookup_ifaddr(pAdapter);
766 if (ifa && ifa->ifa_local)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800767 schedule_work(&pAdapter->ipv4NotifierWorkQueue);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800768 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530769 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800770 return NOTIFY_DONE;
771}
772
773/**
774 * wlan_hdd_ipv4_changed() - IPv4 change notifier callback
775 * @nb: pointer to notifier block
776 * @data: data
777 * @arg: arg
778 *
779 * This is the IPv4 notifier callback function gets invoked
780 * if any change in IP and then invoke the function @__wlan_hdd_ipv4_changed
781 * to reconfigure the offload parameters.
782 *
783 * Return: 0 on success, error number otherwise.
784 */
785int wlan_hdd_ipv4_changed(struct notifier_block *nb,
786 unsigned long data, void *arg)
787{
788 int ret;
789
790 cds_ssr_protect(__func__);
791 ret = __wlan_hdd_ipv4_changed(nb, data, arg);
792 cds_ssr_unprotect(__func__);
793
794 return ret;
795}
796
797/**
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530798 * hdd_get_ipv4_local_interface() - get ipv4 local interafce from iface list
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800799 * @pAdapter: Adapter context for which ARP offload is to be configured
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800800 *
801 * Return:
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530802 * ifa - on successful operation,
803 * NULL - on failure of operation
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800804 */
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530805static struct in_ifaddr *hdd_get_ipv4_local_interface(
806 hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800807{
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530808 struct in_ifaddr **ifap = NULL;
809 struct in_ifaddr *ifa = NULL;
810 struct in_device *in_dev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800811
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530812 in_dev = __in_dev_get_rtnl(pAdapter->dev);
813 if (in_dev) {
814 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
815 ifap = &ifa->ifa_next) {
816 if (!strcmp(pAdapter->dev->name, ifa->ifa_label)) {
817 /* if match break */
818 return ifa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800819 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800820 }
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530821 }
822 ifa = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800823
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530824 return ifa;
825}
826
827void hdd_enable_arp_offload(hdd_adapter_t *adapter,
828 enum pmo_offload_trigger trigger)
829{
830 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
831 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
832 QDF_STATUS status;
833 struct pmo_arp_req *arp_req = NULL;
834 struct in_ifaddr *ifa = NULL;
835
836 ENTER();
837 arp_req = qdf_mem_malloc(sizeof(*arp_req));
838 if (!arp_req) {
839 hdd_err("cannot allocate arp_req");
840 goto out;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800841 }
Jeff Johnson68755312017-02-10 11:46:55 -0800842
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530843 arp_req->psoc = psoc;
844 arp_req->vdev_id = adapter->sessionId;
845 arp_req->trigger = trigger;
Jeff Johnson68755312017-02-10 11:46:55 -0800846
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530847 ifa = hdd_get_ipv4_local_interface(adapter);
848 if (ifa && ifa->ifa_local) {
849 arp_req->ipv4_addr = (uint32_t)ifa->ifa_local;
850 status = pmo_ucfg_cache_arp_offload_req(arp_req);
851 if (status == QDF_STATUS_SUCCESS) {
852 status = pmo_ucfg_enable_arp_offload_in_fwr(
853 adapter->hdd_vdev, trigger);
854 if (status == QDF_STATUS_SUCCESS)
855 hdd_wlan_offload_event(
856 PMO_IPV4_ARP_REPLY_OFFLOAD,
857 PMO_OFFLOAD_ENABLE);
858 else
859 hdd_info("fail to enable arp offload in fwr");
860 } else
861 hdd_info("fail to cache arp offload request");
862 } else {
863 hdd_notice("IP Address is not assigned");
864 status = QDF_STATUS_NOT_INITIALIZED;
865 }
866out:
867 if (arp_req)
868 qdf_mem_free(arp_req);
869 EXIT();
870
871}
872
873void hdd_disable_arp_offload(hdd_adapter_t *adapter,
874 enum pmo_offload_trigger trigger)
875{
876 QDF_STATUS status;
877
878 ENTER();
879 status = pmo_ucfg_flush_arp_offload_req(adapter->hdd_vdev);
880 if (status != QDF_STATUS_SUCCESS) {
881 hdd_err("Failed to flush arp Offload");
882 goto out;
Jeff Johnson68755312017-02-10 11:46:55 -0800883 }
884
Mukul Sharma3ba26b82017-01-12 21:59:41 +0530885 status = pmo_ucfg_disable_arp_offload_in_fwr(adapter->hdd_vdev, trigger);
886 if (status == QDF_STATUS_SUCCESS)
887 hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD,
888 PMO_OFFLOAD_DISABLE);
889 else
890 hdd_info("fail to disable arp offload");
891out:
892 EXIT();
893
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800894}
895
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530896void hdd_enable_mc_addr_filtering(hdd_adapter_t *adapter,
897 enum pmo_offload_trigger trigger)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800898{
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530899 hdd_context_t *hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
900 QDF_STATUS status;
901 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800902
Ravi Joshi24477b72016-07-19 15:45:09 -0700903 ENTER();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530904 if (wlan_hdd_validate_context(hdd_ctx))
905 goto out;
Ravi Joshi24477b72016-07-19 15:45:09 -0700906
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530907 status = pmo_ucfg_enable_mc_addr_filtering_in_fwr(psoc,
908 adapter->sessionId, trigger);
909 if (status != QDF_STATUS_SUCCESS)
910 hdd_info("failed to enable mc list status %d", status);
911out:
Ravi Joshi24477b72016-07-19 15:45:09 -0700912 EXIT();
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530913
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800914}
Mukul Sharmaff2ac2e2017-01-16 15:51:29 +0530915
916void hdd_disable_mc_addr_filtering(hdd_adapter_t *adapter,
917 enum pmo_offload_trigger trigger)
918{
919 hdd_context_t *hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
920 QDF_STATUS status = QDF_STATUS_SUCCESS;
921 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
922
923 ENTER();
924 if (wlan_hdd_validate_context(hdd_ctx))
925 goto out;
926
927 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
928 adapter->sessionId, trigger);
929 if (status != QDF_STATUS_SUCCESS)
930 hdd_info("failed to disable mc list status %d", status);
931out:
932 EXIT();
933
934}
935
936int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config)
937{
938 QDF_STATUS status;
939 int ret = 0;
940
941 ENTER();
942 /* cache mc addr list */
943 status = pmo_ucfg_cache_mc_addr_list(mc_list_config);
944 if (status != QDF_STATUS_SUCCESS) {
945 hdd_info("fail to cache mc list status %d", status);
946 ret = -EINVAL;
947 }
948 EXIT();
949
950 return ret;
951}
952
953void hdd_disable_and_flush_mc_addr_list(hdd_adapter_t *adapter,
954 enum pmo_offload_trigger trigger)
955{
956 hdd_context_t *hdd_ctx = (hdd_context_t *)adapter->pHddCtx;
957 struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
958 QDF_STATUS status = QDF_STATUS_SUCCESS;
959
960 ENTER();
961 /* disable mc list first */
962 status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(psoc,
963 adapter->sessionId, trigger);
964 if (status != QDF_STATUS_SUCCESS)
965 hdd_info("fail to disable mc list");
966
967 /* flush mc list */
968 status = pmo_ucfg_flush_mc_addr_list(psoc, adapter->sessionId);
969 if (status != QDF_STATUS_SUCCESS)
970 hdd_info("fail to flush mc list status %d", status);
971 EXIT();
972
973 return;
974
975}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800976
977/**
Houston Hoffman7260ecb2015-10-05 18:43:07 -0700978 * hdd_update_conn_state_mask(): record info needed by wma_suspend_req
979 * @adapter: adapter to get info from
980 * @conn_state_mask: mask of connection info
981 *
982 * currently only need to send connection info.
983 */
984static void
985hdd_update_conn_state_mask(hdd_adapter_t *adapter, uint32_t *conn_state_mask)
986{
987
988 eConnectionState connState;
989 hdd_station_ctx_t *sta_ctx;
990 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
991 connState = sta_ctx->conn_info.connState;
992
993 if (connState == eConnectionState_Associated ||
994 connState == eConnectionState_IbssConnected)
995 *conn_state_mask |= (1 << adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800996}
997
998/**
999 * hdd_suspend_wlan() - Driver suspend function
1000 * @callback: Callback function to invoke when driver is ready to suspend
1001 * @callbackContext: Context to pass back to @callback function
1002 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301003 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001004 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301005static int
1006hdd_suspend_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001007{
1008 hdd_context_t *pHddCtx;
1009
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301010 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001011 hdd_adapter_t *pAdapter = NULL;
1012 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001013 uint32_t conn_state_mask = 0;
Jeff Johnsonc3273322016-07-06 15:28:17 -07001014 hdd_info("WLAN being suspended by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001015
Anurag Chouhan6d760662016-02-20 16:05:43 +05301016 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001017 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001018 hdd_alert("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301019 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001020 }
1021
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001022 if (cds_is_driver_recovering()) {
1023 hdd_err("Recovery in Progress. State: 0x%x Ignore suspend!!!",
1024 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301025 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001026 }
1027
1028 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301029 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001030 pAdapter = pAdapterNode->pAdapter;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301031 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1032 hdd_err("invalid session id: %d", pAdapter->sessionId);
1033 goto next_adapter;
1034 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001035
1036 /* stop all TX queues before suspend */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001037 hdd_notice("Disabling queues");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001038 wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE,
1039 WLAN_CONTROL_PATH);
1040
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001041 /* Configure supported OffLoads */
Mukul Sharma3ba26b82017-01-12 21:59:41 +05301042 hdd_enable_host_offloads(pAdapter, pmo_apps_suspend);
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001043 hdd_update_conn_state_mask(pAdapter, &conn_state_mask);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301044next_adapter:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001045 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1046 pAdapterNode = pNext;
1047 }
1048
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301049 status = pmo_ucfg_psoc_user_space_suspend_req(pHddCtx->hdd_psoc,
1050 QDF_SYSTEM_SUSPEND);
1051 if (status != QDF_STATUS_SUCCESS)
1052 return -EAGAIN;
Houston Hoffman7260ecb2015-10-05 18:43:07 -07001053
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054 pHddCtx->hdd_wlan_suspended = true;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301055 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001056
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301057 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001058}
1059
1060/**
1061 * hdd_resume_wlan() - Driver resume function
1062 *
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301063 * Return: 0 on success else error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001064 */
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301065static int hdd_resume_wlan(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001066{
1067 hdd_context_t *pHddCtx;
1068 hdd_adapter_t *pAdapter = NULL;
1069 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301070 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001071
Dustin Brown2d228232016-09-22 15:06:19 -07001072 hdd_info("WLAN being resumed by OS");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001073
Anurag Chouhan6d760662016-02-20 16:05:43 +05301074 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001075 if (!pHddCtx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001076 hdd_err("HDD context is Null");
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301077 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001078 }
1079
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001080 if (cds_is_driver_recovering()) {
Dustin Brown2d228232016-09-22 15:06:19 -07001081 hdd_err("Recovery in Progress. State: 0x%x Ignore resume!!!",
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001082 cds_get_driver_state());
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301083 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 }
1085
1086 pHddCtx->hdd_wlan_suspended = false;
Abhishek Singhbaea27d2016-04-27 13:29:30 +05301087 hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001088
1089 /*loop through all adapters. Concurrency */
1090 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
1091
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301092 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001093 pAdapter = pAdapterNode->pAdapter;
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301094 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1095 hdd_err("invalid session id: %d", pAdapter->sessionId);
1096 goto next_adapter;
1097 }
1098 /* Disable supported OffLoads */
1099 hdd_disable_host_offloads(pAdapter, pmo_apps_resume);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001100
1101 /* wake the tx queues */
Dustin Brown2d228232016-09-22 15:06:19 -07001102 hdd_info("Enabling queues");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001103 wlan_hdd_netif_queue_control(pAdapter,
1104 WLAN_WAKE_ALL_NETIF_QUEUE,
1105 WLAN_CONTROL_PATH);
1106
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301107next_adapter:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1109 pAdapterNode = pNext;
1110 }
1111 hdd_ipa_resume(pHddCtx);
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301112 status = pmo_ucfg_psoc_user_space_resume_req(pHddCtx->hdd_psoc,
1113 QDF_SYSTEM_SUSPEND);
1114 if (status != QDF_STATUS_SUCCESS)
1115 return -EAGAIN;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001116
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301117 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118}
1119
1120/**
1121 * DOC: SSR Timer
1122 *
1123 * When SSR is initiated, an SSR timer is started. Under normal
1124 * circumstances SSR should complete amd the timer should be deleted
1125 * before it fires. If the SSR timer does fire, it indicates SSR has
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301126 * taken too long, and our only recourse is to invoke the QDF_BUG()
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001127 * API which can allow a crashdump to be captured.
1128 */
1129
1130/**
1131 * hdd_ssr_timer_init() - Initialize SSR Timer
1132 *
1133 * Return: None.
1134 */
1135static void hdd_ssr_timer_init(void)
1136{
1137 init_timer(&ssr_timer);
1138}
1139
1140/**
1141 * hdd_ssr_timer_del() - Delete SSR Timer
1142 *
1143 * Return: None.
1144 */
1145static void hdd_ssr_timer_del(void)
1146{
1147 del_timer(&ssr_timer);
1148 ssr_timer_started = false;
1149}
1150
1151/**
1152 * hdd_ssr_timer_cb() - SSR Timer callback function
1153 * @data: opaque data registered with timer infrastructure
1154 *
1155 * Return: None.
1156 */
1157static void hdd_ssr_timer_cb(unsigned long data)
1158{
Jeff Johnsonc3273322016-07-06 15:28:17 -07001159 hdd_alert("HDD SSR timer expired!");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301160 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001161}
1162
1163/**
1164 * hdd_ssr_timer_start() - Start SSR Timer
1165 * @msec: Timer timeout value in milliseconds
1166 *
1167 * Return: None.
1168 */
1169static void hdd_ssr_timer_start(int msec)
1170{
1171 if (ssr_timer_started) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001172 hdd_alert("Trying to start SSR timer when " "it's running!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001173 }
1174 ssr_timer.expires = jiffies + msecs_to_jiffies(msec);
1175 ssr_timer.function = hdd_ssr_timer_cb;
1176 add_timer(&ssr_timer);
1177 ssr_timer_started = true;
1178}
1179
1180/**
Komal Seelam78ff65a2016-08-18 15:25:24 +05301181 * hdd_svc_fw_shutdown_ind() - API to send FW SHUTDOWN IND to Userspace
1182 *
1183 * @dev: Device Pointer
1184 *
1185 * Return: None
1186 */
1187void hdd_svc_fw_shutdown_ind(struct device *dev)
1188{
1189 hdd_context_t *hdd_ctx;
1190 v_CONTEXT_t g_context;
1191
1192 g_context = cds_get_global_context();
1193
1194 if (!g_context)
1195 return;
1196
1197 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1198
1199 hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
1200 WLAN_SVC_FW_SHUTDOWN_IND,
1201 NULL, 0) : 0;
1202}
1203
1204/**
Arun Khandavallicc544b32017-01-30 19:52:16 +05301205 * hdd_ssr_restart_sap() - restart sap on SSR
1206 * @hdd_ctx: hdd context
1207 *
1208 * Return: nothing
1209 */
1210static void hdd_ssr_restart_sap(hdd_context_t *hdd_ctx)
1211{
1212 QDF_STATUS status;
1213 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
1214 hdd_adapter_t *adapter;
1215
1216 ENTER();
1217
1218 status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
1219 while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
1220 adapter = adapter_node->pAdapter;
1221 if (adapter && adapter->device_mode == QDF_SAP_MODE) {
Manikandan Mohan0a0ac952017-02-16 15:49:31 -08001222 if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) {
1223 hdd_notice("Restart prev SAP session");
1224 wlan_hdd_start_sap(adapter, true);
1225 }
Arun Khandavallicc544b32017-01-30 19:52:16 +05301226 }
1227 status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next);
1228 adapter_node = next;
1229 }
1230
1231 EXIT();
1232}
1233
1234/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001235 * hdd_wlan_shutdown() - HDD SSR shutdown function
1236 *
1237 * This function is called by the HIF to shutdown the driver during SSR.
1238 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301239 * Return: QDF_STATUS_SUCCESS if the driver was shut down,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001240 * or an error status otherwise
1241 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301242QDF_STATUS hdd_wlan_shutdown(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001243{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001244 v_CONTEXT_t p_cds_context = NULL;
1245 hdd_context_t *pHddCtx;
1246 p_cds_sched_context cds_sched_context = NULL;
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001247 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001248
Jeff Johnsonc3273322016-07-06 15:28:17 -07001249 hdd_alert("WLAN driver shutting down!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001250
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001251 /* If SSR never completes, then do kernel panic. */
1252 hdd_ssr_timer_init();
1253 hdd_ssr_timer_start(HDD_SSR_BRING_UP_TIME);
1254
1255 /* Get the global CDS context. */
1256 p_cds_context = cds_get_global_context();
1257 if (!p_cds_context) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001258 hdd_alert("Global CDS context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301259 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001260 }
1261
1262 /* Get the HDD context. */
Anurag Chouhan6d760662016-02-20 16:05:43 +05301263 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001264 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001265 hdd_alert("HDD context is Null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301266 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001267 }
1268
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001269 cds_clear_concurrent_session_count();
Himanshu Agarwalf65bd4c2016-12-05 17:21:12 +05301270
1271 hdd_info("Invoking packetdump deregistration API");
1272 wlan_deregister_txrx_packetdump();
Sandeep Puligillad0004212017-02-26 18:34:56 -08001273#ifndef NAPIER_SCAN
Sandeep Puligillae390be52016-02-08 17:07:05 -08001274 hdd_cleanup_scan_queue(pHddCtx);
Sandeep Puligillad0004212017-02-26 18:34:56 -08001275#else
1276 wlan_cfg80211_abort_scan(pHddCtx->hdd_pdev);
1277#endif
Govind Singh9c58eba2016-09-02 16:23:06 +05301278 hdd_ipa_uc_ssr_deinit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001279 hdd_reset_all_adapters(pHddCtx);
1280
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301281 /* Flush cached rx frame queue */
Poddar, Siddartha78cac32016-12-29 20:08:34 +05301282 ol_txrx_flush_cache_rx_queue();
Poddar, Siddarth1ab0a3d2016-09-29 18:58:45 +05301283
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301284 /* De-register the HDD callbacks */
1285 hdd_deregister_cb(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001286
1287 cds_sched_context = get_cds_sched_ctxt();
1288
Rajeev Kumareada0d02016-12-08 17:44:17 -08001289 if (pHddCtx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001290 scheduler_resume();
Rajeev Kumareada0d02016-12-08 17:44:17 -08001291 pHddCtx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001292 }
1293#ifdef QCA_CONFIG_SMP
1294 if (true == pHddCtx->is_ol_rx_thread_suspended) {
1295 complete(&cds_sched_context->ol_resume_rx_event);
1296 pHddCtx->is_ol_rx_thread_suspended = false;
1297 }
1298#endif
1299
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001300 qdf_status = cds_sched_close(p_cds_context);
1301 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1302 hdd_err("Failed to close CDS Scheduler");
1303 QDF_ASSERT(false);
1304 }
1305
Nitesh Shah61c10d92016-10-19 19:29:15 +05301306 qdf_mc_timer_stop(&pHddCtx->tdls_source_timer);
1307
Prashanth Bhattaab004382016-10-11 16:08:11 -07001308 hdd_bus_bandwidth_destroy(pHddCtx);
1309
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001310 hdd_wlan_stop_modules(pHddCtx);
Manishekar Chandrasekaranf7a1dad2016-06-23 06:43:47 +05301311
Jeff Johnsonf7f66f02016-09-23 14:50:11 -07001312 hdd_lpass_notify_stop(pHddCtx);
Yuanyuan Liu3e918e52016-08-17 15:41:35 -07001313
Jeff Johnsonc3273322016-07-06 15:28:17 -07001314 hdd_alert("WLAN driver shutdown complete");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301315 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001316}
1317
Sen, Devendra154b3c42017-02-13 20:44:15 +05301318#ifdef FEATURE_WLAN_DIAG_SUPPORT
1319/**
1320* hdd_wlan_ssr_reinit_event()- send ssr reinit state
1321*
1322* This Function send send ssr reinit state diag event
1323*
1324* Return: void.
1325*/
1326static void hdd_wlan_ssr_reinit_event(void)
1327{
1328 WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit);
1329 qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit));
1330 ssr_reinit.status = SSR_SUB_SYSTEM_REINIT;
1331 WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit,
1332 EVENT_WLAN_SSR_REINIT_SUBSYSTEM);
1333}
1334#else
1335static inline void hdd_wlan_ssr_reinit_event(void)
1336{
1337
1338}
1339#endif
1340
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001341/**
1342 * hdd_wlan_re_init() - HDD SSR re-init function
1343 *
1344 * This function is called by the HIF to re-initialize the driver after SSR.
1345 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301346 * Return: QDF_STATUS_SUCCESS if the driver was re-initialized,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001347 * or an error status otherwise
1348 */
Arun Khandavallifae92942016-08-01 13:31:08 +05301349QDF_STATUS hdd_wlan_re_init(void)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001350{
Arun Khandavallifae92942016-08-01 13:31:08 +05301351
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001352 v_CONTEXT_t p_cds_context = NULL;
1353 hdd_context_t *pHddCtx = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001354 hdd_adapter_t *pAdapter;
Arun Khandavallifae92942016-08-01 13:31:08 +05301355 int ret;
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301356 bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001357
1358 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1359
1360 /* Get the CDS context */
1361 p_cds_context = cds_get_global_context();
1362 if (p_cds_context == NULL) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001363 hdd_alert("Failed cds_get_global_context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001364 goto err_re_init;
1365 }
1366
1367 /* Get the HDD context */
Anurag Chouhan6d760662016-02-20 16:05:43 +05301368 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001369 if (!pHddCtx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001370 hdd_alert("HDD context is Null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001371 goto err_re_init;
1372 }
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301373 bug_on_reinit_failure = pHddCtx->config->bug_on_reinit_failure;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001374
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001375 /* The driver should always be initialized in STA mode after SSR */
1376 hdd_set_conparam(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001377 /* Try to get an adapter from mode ID */
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001378 pAdapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001379 if (!pAdapter) {
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001380 pAdapter = hdd_get_adapter(pHddCtx, QDF_SAP_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001381 if (!pAdapter) {
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001382 pAdapter = hdd_get_adapter(pHddCtx, QDF_IBSS_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001383 if (!pAdapter) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001384 hdd_alert("Failed to get Adapter!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001385 }
1386 }
1387 }
1388
Nirav Shahcc1f1ae2016-04-26 11:41:29 +05301389 if (pHddCtx->config->enable_dp_trace)
1390 qdf_dp_trace_init();
1391
Prashanth Bhattaab004382016-10-11 16:08:11 -07001392 hdd_bus_bandwidth_init(pHddCtx);
1393
Arun Khandavallicc544b32017-01-30 19:52:16 +05301394
Arun Khandavallifae92942016-08-01 13:31:08 +05301395 ret = hdd_wlan_start_modules(pHddCtx, pAdapter, true);
1396 if (ret) {
1397 hdd_err("Failed to start wlan after error");
1398 goto err_wiphy_unregister;
1399 }
1400
Arun Khandavallia96c2c02016-05-17 19:15:34 +05301401 hdd_wlan_get_version(pHddCtx, NULL, NULL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001402
Wu Gao36717432016-11-21 15:09:48 +08001403 wlan_hdd_send_svc_nlink_msg(pHddCtx->radio_index,
1404 WLAN_SVC_FW_CRASHED_IND, NULL, 0);
1405
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001406 /* Restart all adapters */
1407 hdd_start_all_adapters(pHddCtx);
1408
Sreelakshmi Konamkib53c6292017-03-01 13:13:23 +05301409 pHddCtx->last_scan_reject_session_id = 0xFF;
1410 pHddCtx->last_scan_reject_reason = 0;
1411 pHddCtx->last_scan_reject_timestamp = 0;
1412
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001413 pHddCtx->btCoexModeSet = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001414
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001415 /* Allow the phone to go to sleep */
1416 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
1417
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301418 ret = hdd_register_cb(pHddCtx);
1419 if (ret) {
1420 hdd_err("Failed to register HDD callbacks!");
Chandrasekaran Manishekarcde33d72016-04-14 19:03:39 +05301421 goto err_cds_disable;
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301422 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001423
Jeff Johnson9afc5012016-09-23 13:56:27 -07001424 hdd_lpass_notify_start(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001425
Jeff Johnsonc3273322016-07-06 15:28:17 -07001426 hdd_err("WLAN host driver reinitiation completed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001427 goto success;
1428
1429err_cds_disable:
Prashanth Bhatta2ac92bd2016-10-11 16:08:00 -07001430 hdd_wlan_stop_modules(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001431
Arun Khandavallifae92942016-08-01 13:31:08 +05301432err_wiphy_unregister:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001433 if (pHddCtx) {
1434 /* Unregister the Net Device Notifier */
1435 unregister_netdevice_notifier(&hdd_netdev_notifier);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001436 ptt_sock_deactivate_svc();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001437 nl_srv_exit();
1438
1439 /* Free up dynamically allocated members inside HDD Adapter */
Mahesh Kumar Kalikot Veetil9c656182016-11-02 10:28:03 -07001440 qdf_mem_free(pHddCtx->config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001441 pHddCtx->config = NULL;
Nirav Shahed34b212016-04-25 10:59:16 +05301442 wlan_hdd_deinit_tx_rx_histogram(pHddCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001443 wiphy_unregister(pHddCtx->wiphy);
1444 wiphy_free(pHddCtx->wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001445 }
1446
1447err_re_init:
1448 /* Allow the phone to go to sleep */
1449 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
Mukul Sharmaf7d62e12016-09-03 15:16:22 +05301450 if (bug_on_reinit_failure)
1451 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001452 return -EPERM;
1453
1454success:
Arun Khandavallicc544b32017-01-30 19:52:16 +05301455 if (pHddCtx->config->sap_internal_restart)
1456 hdd_ssr_restart_sap(pHddCtx);
Srinivas Girigowda02c084d2016-10-18 15:27:21 -07001457 hdd_ssr_timer_del();
Sen, Devendra154b3c42017-02-13 20:44:15 +05301458 hdd_wlan_ssr_reinit_event();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301459 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001460}
1461
1462/**
1463 * wlan_hdd_set_powersave() - Set powersave mode
1464 * @adapter: adapter upon which the request was received
Dustin Brownf660fb42016-09-09 12:04:00 -07001465 * @allow_power_save: is wlan allowed to go into power save mode
1466 * @timeout: timeout period in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001467 *
1468 * Return: 0 on success, non-zero on any error
1469 */
Dustin Brownf660fb42016-09-09 12:04:00 -07001470static int wlan_hdd_set_powersave(hdd_adapter_t *adapter,
1471 bool allow_power_save, uint32_t timeout)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001472{
1473 tHalHandle hal;
1474 hdd_context_t *hdd_ctx;
1475
1476 if (NULL == adapter) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001477 hdd_alert("Adapter NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001478 return -ENODEV;
1479 }
1480
1481 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1482 if (!hdd_ctx) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001483 hdd_err("hdd context is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001484 return -EINVAL;
1485 }
1486
Dustin Brownf660fb42016-09-09 12:04:00 -07001487 hdd_info("Allow power save: %d", allow_power_save);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001488 hal = WLAN_HDD_GET_HAL_CTX(adapter);
1489
Dustin Brownf660fb42016-09-09 12:04:00 -07001490 if (allow_power_save) {
1491 if (QDF_STA_MODE == adapter->device_mode ||
1492 QDF_P2P_CLIENT_MODE == adapter->device_mode) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001493 hdd_notice("Disabling Auto Power save timer");
Dustin Brownf660fb42016-09-09 12:04:00 -07001494 sme_ps_disable_auto_ps_timer(
1495 WLAN_HDD_GET_HAL_CTX(adapter),
1496 adapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001497 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001498
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001499 if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001500 hdd_notice("Wlan driver Entering Power save");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001501
1502 /*
1503 * Enter Power Save command received from GUI
1504 * this means DHCP is completed
1505 */
1506 sme_ps_enable_disable(hal, adapter->sessionId,
1507 SME_PS_ENABLE);
1508 } else {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001509 hdd_info("Power Save is not enabled in the cfg");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001510 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001511 } else {
1512 hdd_info("Wlan driver Entering Full Power");
1513
1514 /*
1515 * Enter Full power command received from GUI
1516 * this means we are disconnected
1517 */
1518 sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1519 adapter->sessionId);
1520 sme_ps_enable_disable(hal, adapter->sessionId, SME_PS_DISABLE);
1521 sme_ps_enable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter),
1522 adapter->sessionId, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001523 }
Dustin Brownf660fb42016-09-09 12:04:00 -07001524
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001525 return 0;
1526}
1527
Dustin Brown105d7902016-10-03 16:27:59 -07001528static void wlan_hdd_print_suspend_fail_stats(hdd_context_t *hdd_ctx)
1529{
Dustin Brownd9322482017-01-09 12:46:03 -08001530 struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats;
Dustin Brown105d7902016-10-03 16:27:59 -07001531 hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d",
Dustin Brownd9322482017-01-09 12:46:03 -08001532 stats->suspend_fail[SUSPEND_FAIL_IPA],
1533 stats->suspend_fail[SUSPEND_FAIL_RADAR],
1534 stats->suspend_fail[SUSPEND_FAIL_ROAM],
1535 stats->suspend_fail[SUSPEND_FAIL_SCAN],
1536 stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]);
Dustin Brown105d7902016-10-03 16:27:59 -07001537}
1538
1539void wlan_hdd_inc_suspend_stats(hdd_context_t *hdd_ctx,
1540 enum suspend_fail_reason reason)
1541{
1542 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
Dustin Brownd9322482017-01-09 12:46:03 -08001543 hdd_ctx->suspend_resume_stats.suspend_fail[reason]++;
Dustin Brown105d7902016-10-03 16:27:59 -07001544 wlan_hdd_print_suspend_fail_stats(hdd_ctx);
1545}
1546
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001547/**
1548 * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1549 * @wiphy: Pointer to wiphy
1550 *
1551 * This API is called when cfg80211 driver resumes driver updates
1552 * latest sched_scan scan result(if any) to cfg80211 database
1553 *
1554 * Return: integer status
1555 */
1556static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1557{
1558 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1559 hdd_adapter_t *pAdapter;
1560 hdd_adapter_list_node_t *pAdapterNode, *pNext;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301561 QDF_STATUS status = QDF_STATUS_SUCCESS;
Dustin Brownd9322482017-01-09 12:46:03 -08001562 int exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001563 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1564
1565 ENTER();
1566
Dustin Brownd9322482017-01-09 12:46:03 -08001567 if (cds_is_driver_recovering()) {
1568 hdd_info("Driver is recovering; Skipping resume");
1569 exit_code = 0;
1570 goto exit_with_code;
1571 }
Prashanth Bhatta697dd0c2016-10-20 18:42:41 -07001572
Anurag Chouhan6d760662016-02-20 16:05:43 +05301573 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001574 hdd_err("Command not allowed in FTM mode");
Dustin Brownd9322482017-01-09 12:46:03 -08001575 exit_code = -EINVAL;
1576 goto exit_with_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001577 }
1578
Dustin Brownd9322482017-01-09 12:46:03 -08001579 exit_code = wlan_hdd_validate_context(pHddCtx);
1580 if (exit_code) {
1581 hdd_err("Invalid HDD context");
1582 goto exit_with_code;
1583 }
Arun Khandavallifae92942016-08-01 13:31:08 +05301584
1585 mutex_lock(&pHddCtx->iface_change_lock);
1586 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
1587 mutex_unlock(&pHddCtx->iface_change_lock);
Dustin Brownd9322482017-01-09 12:46:03 -08001588 hdd_info("Driver is not enabled; Skipping resume");
1589 exit_code = 0;
1590 goto exit_with_code;
Arun Khandavallifae92942016-08-01 13:31:08 +05301591 }
1592 mutex_unlock(&pHddCtx->iface_change_lock);
Dustin Brownd9322482017-01-09 12:46:03 -08001593
Yuanyuan Liu13738502016-04-06 17:41:37 -07001594 pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_MEDIUM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001595
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301596 status = hdd_resume_wlan();
1597 if (status != QDF_STATUS_SUCCESS) {
1598 exit_code = 0;
1599 goto exit_with_code;
1600 }
Rajeev Kumareada0d02016-12-08 17:44:17 -08001601 /* Resume control path scheduler */
1602 if (pHddCtx->is_scheduler_suspended) {
Rajeev Kumar0b732952016-12-08 17:51:39 -08001603 scheduler_resume();
Rajeev Kumareada0d02016-12-08 17:44:17 -08001604 pHddCtx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001605 }
1606#ifdef QCA_CONFIG_SMP
1607 /* Resume tlshim Rx thread */
1608 if (pHddCtx->is_ol_rx_thread_suspended) {
1609 complete(&cds_sched_context->ol_resume_rx_event);
1610 pHddCtx->is_ol_rx_thread_suspended = false;
1611 }
1612#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301614 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301615 TRACE_CODE_HDD_CFG80211_RESUME_WLAN,
1616 NO_SESSION, pHddCtx->isWiphySuspended));
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301617 qdf_spin_lock(&pHddCtx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001618 pHddCtx->isWiphySuspended = false;
1619 if (true != pHddCtx->isSchedScanUpdatePending) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301620 qdf_spin_unlock(&pHddCtx->sched_scan_lock);
Dustin Brown2d228232016-09-22 15:06:19 -07001621 hdd_info("Return resume is not due to PNO indication");
Dustin Brownd9322482017-01-09 12:46:03 -08001622 goto exit_with_success;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001623 }
1624 /* Reset flag to avoid updatating cfg80211 data old results again */
1625 pHddCtx->isSchedScanUpdatePending = false;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301626 qdf_spin_unlock(&pHddCtx->sched_scan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001627
1628 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301629 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001630 pAdapter = pAdapterNode->pAdapter;
1631 if ((NULL != pAdapter) &&
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001632 (QDF_STA_MODE == pAdapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001633 if (0 !=
1634 wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy,
1635 pAdapter, 0)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001636 hdd_warn("NO SCAN result");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001637 } else {
1638 /* Acquire wakelock to handle the case where
1639 * APP's tries to suspend immediately after
1640 * updating the scan results. Whis results in
1641 * app's is in suspended state and not able to
1642 * process the connect request to AP
1643 */
Sreelakshmi Konamki22528532016-09-06 16:34:50 +05301644 hdd_prevent_suspend_timeout(
1645 HDD_WAKE_LOCK_RESUME_DURATION,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001646 WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN);
1647 cfg80211_sched_scan_results(pHddCtx->wiphy);
1648 }
1649
Dustin Brown2d228232016-09-22 15:06:19 -07001650 hdd_info("cfg80211 scan result database updated");
Dustin Brownd9322482017-01-09 12:46:03 -08001651 goto exit_with_success;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001652 }
1653 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1654 pAdapterNode = pNext;
1655 }
1656
Dustin Brownd9322482017-01-09 12:46:03 -08001657exit_with_success:
1658 pHddCtx->suspend_resume_stats.resumes++;
1659 exit_code = 0;
1660
1661exit_with_code:
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301662 EXIT();
Dustin Brownd9322482017-01-09 12:46:03 -08001663 return exit_code;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001664}
1665
1666/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001667 * wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback
1668 * @wiphy: Pointer to wiphy
1669 *
1670 * This API is called when cfg80211 driver resumes driver updates
1671 * latest sched_scan scan result(if any) to cfg80211 database
1672 *
1673 * Return: integer status
1674 */
1675int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
1676{
1677 int ret;
1678
1679 cds_ssr_protect(__func__);
1680 ret = __wlan_hdd_cfg80211_resume_wlan(wiphy);
1681 cds_ssr_unprotect(__func__);
1682
1683 return ret;
1684}
1685
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001686static void hdd_suspend_cb(void)
1687{
1688 hdd_context_t *hdd_ctx;
1689
1690 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1691 if (!hdd_ctx) {
1692 cds_err("HDD context is NULL");
1693 return;
1694 }
1695
1696 complete(&hdd_ctx->mc_sus_event_var);
1697}
1698
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001699/**
1700 * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1701 * @wiphy: Pointer to wiphy
1702 * @wow: Pointer to wow
1703 *
1704 * This API is called when cfg80211 driver suspends
1705 *
1706 * Return: integer status
1707 */
1708static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1709 struct cfg80211_wowlan *wow)
1710{
1711#ifdef QCA_CONFIG_SMP
1712#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */
1713#endif
1714 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1715 p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
1716 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
1717 hdd_adapter_t *pAdapter;
1718 hdd_scaninfo_t *pScanInfo;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301719 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001720 int rc;
1721
1722 ENTER();
1723
Anurag Chouhan6d760662016-02-20 16:05:43 +05301724 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001725 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001726 return -EINVAL;
1727 }
1728
1729 rc = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301730 if (0 != rc)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001731 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732
Arun Khandavallifae92942016-08-01 13:31:08 +05301733 mutex_lock(&pHddCtx->iface_change_lock);
1734 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
1735 mutex_unlock(&pHddCtx->iface_change_lock);
1736 hdd_info("Driver Modules not Enabled ");
1737 return 0;
1738 }
1739 mutex_unlock(&pHddCtx->iface_change_lock);
1740
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001741 /* If RADAR detection is in progress (HDD), prevent suspend. The flag
1742 * "dfs_cac_block_tx" is set to true when RADAR is found and stay true
1743 * until CAC is done for a SoftAP which is in started state.
1744 */
1745 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301746 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001747 pAdapter = pAdapterNode->pAdapter;
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301748
1749 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1750 hdd_err("invalid session id: %d", pAdapter->sessionId);
1751 goto next_adapter;
1752 }
1753
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001754 if (QDF_SAP_MODE == pAdapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001755 if (BSS_START ==
1756 WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter)->bssState &&
1757 true ==
1758 WLAN_HDD_GET_AP_CTX_PTR(pAdapter)->
1759 dfs_cac_block_tx) {
Dustin Brown2d228232016-09-22 15:06:19 -07001760 hdd_err("RADAR detection in progress, do not allow suspend");
Dustin Brown105d7902016-10-03 16:27:59 -07001761 wlan_hdd_inc_suspend_stats(pHddCtx,
1762 SUSPEND_FAIL_RADAR);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763 return -EAGAIN;
1764 } else if (!pHddCtx->config->enableSapSuspend) {
1765 /* return -EOPNOTSUPP if SAP does not support
1766 * suspend
1767 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001768 hdd_err("SAP does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001769 return -EOPNOTSUPP;
1770 }
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001771 } else if (QDF_P2P_GO_MODE == pAdapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001772 if (!pHddCtx->config->enableSapSuspend) {
1773 /* return -EOPNOTSUPP if GO does not support
1774 * suspend
1775 */
Jeff Johnsonc3273322016-07-06 15:28:17 -07001776 hdd_err("GO does not support suspend!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001777 return -EOPNOTSUPP;
1778 }
1779 }
Masti, Narayanraddi3e26de62016-08-19 14:33:22 +05301780 if (pAdapter->is_roc_inprogress)
1781 wlan_hdd_cleanup_remain_on_channel_ctx(pAdapter);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301782next_adapter:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001783 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1784 pAdapterNode = pNext;
1785 }
1786
1787 /* Stop ongoing scan on each interface */
1788 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301789 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001790 pAdapter = pAdapterNode->pAdapter;
1791 pScanInfo = &pAdapter->scan_info;
1792
Sandeep Puligillaf8527122016-11-16 18:35:16 -08001793 if (sme_neighbor_middle_of_roaming
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794 (pHddCtx->hHal, pAdapter->sessionId)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001795 hdd_err("Roaming in progress, do not allow suspend");
Dustin Brown105d7902016-10-03 16:27:59 -07001796 wlan_hdd_inc_suspend_stats(pHddCtx,
1797 SUSPEND_FAIL_ROAM);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798 return -EAGAIN;
1799 }
1800
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001801 if (pScanInfo->mScanPending) {
1802 INIT_COMPLETION(pScanInfo->abortscan_event_var);
1803 hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId,
yeshwanth sriram guntuka310b3ac2016-11-15 23:25:26 +05301804 INVALID_SCAN_ID,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001805 eCSR_SCAN_ABORT_DEFAULT);
1806
1807 status =
1808 wait_for_completion_timeout(&pScanInfo->
1809 abortscan_event_var,
1810 msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN));
1811 if (!status) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001812 hdd_err("Timeout occurred while waiting for abort scan");
Dustin Brown105d7902016-10-03 16:27:59 -07001813 wlan_hdd_inc_suspend_stats(pHddCtx,
1814 SUSPEND_FAIL_SCAN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001815 return -ETIME;
1816 }
1817 }
1818 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
1819 pAdapterNode = pNext;
1820 }
1821
1822 /*
1823 * Suspend IPA early before proceeding to suspend other entities like
1824 * firmware to avoid any race conditions.
1825 */
1826 if (hdd_ipa_suspend(pHddCtx)) {
Dustin Brown2d228232016-09-22 15:06:19 -07001827 hdd_err("IPA not ready to suspend!");
Dustin Brown105d7902016-10-03 16:27:59 -07001828 wlan_hdd_inc_suspend_stats(pHddCtx, SUSPEND_FAIL_IPA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001829 return -EAGAIN;
1830 }
1831
Rajeev Kumareada0d02016-12-08 17:44:17 -08001832 /* Suspend control path scheduler */
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001833 scheduler_register_hdd_suspend_callback(hdd_suspend_cb);
1834 scheduler_set_event_mask(MC_SUSPEND_EVENT_MASK);
1835 scheduler_wake_up_controller_thread();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001836
Rajeev Kumareada0d02016-12-08 17:44:17 -08001837 /* Wait for suspend confirmation from scheduler */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001838 rc = wait_for_completion_timeout(&pHddCtx->mc_sus_event_var,
1839 msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND));
1840 if (!rc) {
Krunal Sonid32c6bc2016-10-18 18:00:21 -07001841 scheduler_clear_event_mask(MC_SUSPEND_EVENT_MASK);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001842 hdd_err("Failed to stop mc thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001843 goto resume_tx;
1844 }
Rajeev Kumareada0d02016-12-08 17:44:17 -08001845 pHddCtx->is_scheduler_suspended = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001846
1847#ifdef QCA_CONFIG_SMP
1848 /* Suspend tlshim rx thread */
1849 set_bit(RX_SUSPEND_EVENT_MASK, &cds_sched_context->ol_rx_event_flag);
1850 wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue);
1851 rc = wait_for_completion_timeout(&cds_sched_context->
1852 ol_suspend_rx_event,
1853 msecs_to_jiffies
1854 (RX_TLSHIM_SUSPEND_TIMEOUT));
1855 if (!rc) {
1856 clear_bit(RX_SUSPEND_EVENT_MASK,
1857 &cds_sched_context->ol_rx_event_flag);
Jeff Johnsonc3273322016-07-06 15:28:17 -07001858 hdd_err("Failed to stop tl_shim rx thread");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001859 goto resume_all;
1860 }
1861 pHddCtx->is_ol_rx_thread_suspended = true;
1862#endif
Mukul Sharma4c60a7e2017-03-06 19:42:18 +05301863 if (hdd_suspend_wlan() < 0)
1864 goto resume_all;
1865
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301866 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05301867 TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN,
1868 NO_SESSION, pHddCtx->isWiphySuspended));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001869 pHddCtx->isWiphySuspended = true;
1870
Yuanyuan Liu13738502016-04-06 17:41:37 -07001871 pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_NONE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001872
1873 EXIT();
1874 return 0;
1875
1876#ifdef QCA_CONFIG_SMP
1877resume_all:
1878
Rajeev Kumar0b732952016-12-08 17:51:39 -08001879 scheduler_resume();
Rajeev Kumareada0d02016-12-08 17:44:17 -08001880 pHddCtx->is_scheduler_suspended = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001881#endif
1882
1883resume_tx:
1884
1885 hdd_resume_wlan();
1886 return -ETIME;
1887
1888}
1889
1890/**
1891 * wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback
1892 * @wiphy: Pointer to wiphy
1893 * @wow: Pointer to wow
1894 *
1895 * This API is called when cfg80211 driver suspends
1896 *
1897 * Return: integer status
1898 */
1899int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
1900 struct cfg80211_wowlan *wow)
1901{
1902 int ret;
1903
1904 cds_ssr_protect(__func__);
1905 ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow);
1906 cds_ssr_unprotect(__func__);
1907
1908 return ret;
1909}
1910
1911/**
Komal Seelama89be8d2016-09-29 11:09:26 +05301912 * hdd_stop_dhcp_ind() - API to stop DHCP sequence
1913 * @adapter: Adapter on which DHCP needs to be stopped
1914 *
1915 * Release the wakelock held for DHCP process and allow
1916 * the runtime pm to continue
1917 *
1918 * Return: None
1919 */
1920static void hdd_stop_dhcp_ind(hdd_adapter_t *adapter)
1921{
1922 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1923
1924 hdd_warn("DHCP stop indicated through power save");
1925 sme_dhcp_stop_ind(hdd_ctx->hHal, adapter->device_mode,
1926 adapter->macAddressCurrent.bytes,
1927 adapter->sessionId);
1928 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP);
1929 qdf_runtime_pm_allow_suspend(adapter->connect_rpm_ctx.connect);
1930}
1931
1932/**
1933 * hdd_start_dhcp_ind() - API to start DHCP sequence
1934 * @adapter: Adapter on which DHCP needs to be stopped
1935 *
1936 * Prevent APPS suspend and the runtime suspend during
1937 * DHCP sequence
1938 *
1939 * Return: None
1940 */
1941static void hdd_start_dhcp_ind(hdd_adapter_t *adapter)
1942{
1943 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1944
1945 hdd_err("DHCP start indicated through power save");
1946 qdf_runtime_pm_prevent_suspend(adapter->connect_rpm_ctx.connect);
1947 hdd_prevent_suspend_timeout(1000, WIFI_POWER_EVENT_WAKELOCK_DHCP);
1948 sme_dhcp_start_ind(hdd_ctx->hHal, adapter->device_mode,
1949 adapter->macAddressCurrent.bytes,
1950 adapter->sessionId);
1951}
1952
1953/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954 * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
1955 * @wiphy: Pointer to wiphy
1956 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07001957 * @allow_power_save: is wlan allowed to go into power save mode
1958 * @timeout: Timeout value in ms
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001959 *
1960 * Return: 0 for success, non-zero for failure
1961 */
1962static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07001963 struct net_device *dev,
1964 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965 int timeout)
1966{
1967 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1968 hdd_context_t *pHddCtx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001969 int status;
1970
Dustin Brownecfce632016-09-13 10:41:45 -07001971 ENTER();
1972
Dustin Brownf660fb42016-09-09 12:04:00 -07001973 if (timeout < 0) {
1974 hdd_notice("User space timeout: %d; Using default instead: %d",
1975 timeout, AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE);
1976 timeout = AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE;
1977 }
1978
Anurag Chouhan6d760662016-02-20 16:05:43 +05301979 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07001980 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001981 return -EINVAL;
1982 }
1983
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301984 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1985 hdd_err("invalid session id: %d", pAdapter->sessionId);
1986 return -EINVAL;
1987 }
1988
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301989 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001990 TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT,
1991 pAdapter->sessionId, timeout));
1992
1993 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1994 status = wlan_hdd_validate_context(pHddCtx);
1995
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301996 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001997 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001998
Arun Khandavalli99286452016-08-22 12:13:41 +05301999 mutex_lock(&pHddCtx->iface_change_lock);
2000 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
2001 mutex_unlock(&pHddCtx->iface_change_lock);
2002 hdd_info("Driver Module not enabled return success");
2003 return 0;
2004 }
2005 mutex_unlock(&pHddCtx->iface_change_lock);
2006
Dustin Brownf660fb42016-09-09 12:04:00 -07002007 status = wlan_hdd_set_powersave(pAdapter, allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002008
Komal Seelama89be8d2016-09-29 11:09:26 +05302009 allow_power_save ? hdd_stop_dhcp_ind(pAdapter) :
2010 hdd_start_dhcp_ind(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011
2012 EXIT();
2013 return status;
2014}
2015
2016/**
2017 * wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config
2018 * @wiphy: Pointer to wiphy
2019 * @dev: Pointer to network device
Dustin Brownf660fb42016-09-09 12:04:00 -07002020 * @allow_power_save: is wlan allowed to go into power save mode
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002021 * @timeout: Timeout value
2022 *
2023 * Return: 0 for success, non-zero for failure
2024 */
2025int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy,
Dustin Brownf660fb42016-09-09 12:04:00 -07002026 struct net_device *dev,
2027 bool allow_power_save,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002028 int timeout)
2029{
2030 int ret;
2031
2032 cds_ssr_protect(__func__);
Dustin Brownf660fb42016-09-09 12:04:00 -07002033 ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev,
2034 allow_power_save, timeout);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002035 cds_ssr_unprotect(__func__);
2036
2037 return ret;
2038}
2039
2040/**
2041 * __wlan_hdd_cfg80211_set_txpower() - set TX power
2042 * @wiphy: Pointer to wiphy
2043 * @wdev: Pointer to network device
2044 * @type: TX power setting type
2045 * @dbm: TX power in dbm
2046 *
2047 * Return: 0 for success, non-zero for failure
2048 */
2049static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002050 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051 enum nl80211_tx_power_setting type,
2052 int dbm)
2053{
2054 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
2055 tHalHandle hHal = NULL;
Anurag Chouhan6d760662016-02-20 16:05:43 +05302056 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
2057 struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002058 int status;
2059
2060 ENTER();
2061
Anurag Chouhan6d760662016-02-20 16:05:43 +05302062 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002063 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002064 return -EINVAL;
2065 }
2066
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302067 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002068 TRACE_CODE_HDD_CFG80211_SET_TXPOWER,
2069 NO_SESSION, type));
2070
2071 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302072 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002073 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002074
2075 hHal = pHddCtx->hHal;
2076
2077 if (0 != sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, dbm)) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002078 hdd_err("sme_cfg_set_int failed for tx power %hu",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002079 dbm);
2080 return -EIO;
2081 }
2082
Jeff Johnsonc3273322016-07-06 15:28:17 -07002083 hdd_info("Set tx power level %d dbm", dbm);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084
2085 switch (type) {
2086 /* Automatically determine transmit power */
2087 case NL80211_TX_POWER_AUTOMATIC:
2088 /* Fall through */
2089 case NL80211_TX_POWER_LIMITED: /* Limit TX power by the mBm parameter */
2090 if (sme_set_max_tx_power(hHal, bssid, selfMac, dbm) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302091 QDF_STATUS_SUCCESS) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002092 hdd_err("Setting maximum tx power failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002093 return -EIO;
2094 }
2095 break;
2096
2097 case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */
Jeff Johnsonc3273322016-07-06 15:28:17 -07002098 hdd_err("NL80211_TX_POWER_FIXED not supported");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002099 return -EOPNOTSUPP;
2100 break;
2101
2102 default:
Jeff Johnsonc3273322016-07-06 15:28:17 -07002103 hdd_err("Invalid power setting type %d", type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002104 return -EIO;
2105 }
2106
2107 EXIT();
2108 return 0;
2109}
2110
2111/**
2112 * wlan_hdd_cfg80211_set_txpower() - set TX power
2113 * @wiphy: Pointer to wiphy
2114 * @wdev: Pointer to network device
2115 * @type: TX power setting type
2116 * @dbm: TX power in dbm
2117 *
2118 * Return: 0 for success, non-zero for failure
2119 */
2120int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002121 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002122 enum nl80211_tx_power_setting type,
2123 int dbm)
2124{
2125 int ret;
2126 cds_ssr_protect(__func__);
2127 ret = __wlan_hdd_cfg80211_set_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002128 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002129 type, dbm);
2130 cds_ssr_unprotect(__func__);
2131
2132 return ret;
2133}
2134
2135/**
2136 * __wlan_hdd_cfg80211_get_txpower() - get TX power
2137 * @wiphy: Pointer to wiphy
2138 * @wdev: Pointer to network device
2139 * @dbm: Pointer to TX power in dbm
2140 *
2141 * Return: 0 for success, non-zero for failure
2142 */
2143static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002144 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002145 int *dbm)
2146{
2147
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002148 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
Arun Khandavalli99286452016-08-22 12:13:41 +05302149 struct net_device *ndev = wdev->netdev;
2150 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002151 int status;
2152
2153 ENTER();
2154
Anurag Chouhan6d760662016-02-20 16:05:43 +05302155 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnsonc3273322016-07-06 15:28:17 -07002156 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002157 return -EINVAL;
2158 }
2159
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302160 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2161 hdd_err("invalid session id: %d", adapter->sessionId);
2162 return -EINVAL;
2163 }
2164
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002165 status = wlan_hdd_validate_context(pHddCtx);
2166 if (0 != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002167 *dbm = 0;
2168 return status;
2169 }
2170
Arun Khandavalli99286452016-08-22 12:13:41 +05302171 /* Validate adapter sessionId */
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302172 if (wlan_hdd_validate_session_id(adapter->sessionId)) {
2173 hdd_err("invalid session id: %d", adapter->sessionId);
Arun Khandavalli99286452016-08-22 12:13:41 +05302174 return -ENOTSUPP;
2175 }
2176
2177 mutex_lock(&pHddCtx->iface_change_lock);
2178 if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
2179 mutex_unlock(&pHddCtx->iface_change_lock);
2180 hdd_info("Driver Module not enabled return success");
2181 /* Send cached data to upperlayer*/
2182 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
2183 return 0;
2184 }
2185 mutex_unlock(&pHddCtx->iface_change_lock);
2186
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302187 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +05302188 TRACE_CODE_HDD_CFG80211_GET_TXPOWER,
Arun Khandavalli99286452016-08-22 12:13:41 +05302189 adapter->sessionId, adapter->device_mode));
2190 wlan_hdd_get_class_astats(adapter);
2191 *dbm = adapter->hdd_stats.ClassA_stat.max_pwr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002192
2193 EXIT();
2194 return 0;
2195}
2196
2197/**
2198 * wlan_hdd_cfg80211_get_txpower() - cfg80211 get power handler function
2199 * @wiphy: Pointer to wiphy structure.
2200 * @wdev: Pointer to wireless_dev structure.
2201 * @dbm: dbm
2202 *
2203 * This is the cfg80211 get txpower handler function which invokes
2204 * the internal function @__wlan_hdd_cfg80211_get_txpower with
2205 * SSR protection.
2206 *
2207 * Return: 0 for success, error number on failure.
2208 */
2209int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002210 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211 int *dbm)
2212{
2213 int ret;
2214
2215 cds_ssr_protect(__func__);
2216 ret = __wlan_hdd_cfg80211_get_txpower(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002217 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002218 dbm);
2219 cds_ssr_unprotect(__func__);
2220
2221 return ret;
2222}
Kapil Gupta6213c012016-09-02 19:39:09 +05302223
2224/**
2225 * hdd_set_qpower_config() - set qpower config to firmware
2226 * @adapter: HDD adapter
2227 * @qpower: new qpower config value
2228 *
2229 * Return: 0 on success; Errno on failure
2230 */
2231int hdd_set_qpower_config(hdd_context_t *hddctx, hdd_adapter_t *adapter,
Dustin Brown10a7b712016-10-07 10:31:16 -07002232 u8 qpower)
Kapil Gupta6213c012016-09-02 19:39:09 +05302233{
Dustin Brown10a7b712016-10-07 10:31:16 -07002234 QDF_STATUS status;
Kapil Gupta6213c012016-09-02 19:39:09 +05302235
2236 if (!hddctx->config->enablePowersaveOffload) {
2237 hdd_err("qpower is disabled in configuration");
2238 return -EINVAL;
2239 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002240
Kapil Gupta6213c012016-09-02 19:39:09 +05302241 if (qpower > PS_DUTY_CYCLING_QPOWER ||
2242 qpower < PS_LEGACY_NODEEPSLEEP) {
Dustin Brown10a7b712016-10-07 10:31:16 -07002243 hdd_err("invalid qpower value: %d", qpower);
Kapil Gupta6213c012016-09-02 19:39:09 +05302244 return -EINVAL;
2245 }
Kapil Gupta6213c012016-09-02 19:39:09 +05302246
Dustin Brown10a7b712016-10-07 10:31:16 -07002247 status = wma_set_qpower_config(adapter->sessionId, qpower);
2248 if (status != QDF_STATUS_SUCCESS) {
2249 hdd_err("failed to configure qpower: %d", status);
2250 return -EINVAL;
Kapil Gupta6213c012016-09-02 19:39:09 +05302251 }
Dustin Brown10a7b712016-10-07 10:31:16 -07002252
Kapil Gupta6213c012016-09-02 19:39:09 +05302253 return 0;
2254}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002255
Dustin Brown54096432017-02-23 13:00:44 -08002256
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002257#ifdef WLAN_SUSPEND_RESUME_TEST
2258/*
Dustin Brownd53d1a82016-10-03 12:57:33 -07002259 * On iHelium there are 12 CE irqs and #2 is the wake irq. This may not be
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002260 * a valid assumption on future platforms.
2261 */
2262#define CE_IRQ_COUNT 12
2263#define CE_WAKE_IRQ 2
Dustin Brownbc81a472016-10-26 16:56:59 -07002264static struct net_device *g_dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002265static struct wiphy *g_wiphy;
2266
2267#define HDD_FA_SUSPENDED_BIT (0)
2268static unsigned long fake_apps_state;
2269
Dustin Brownd53d1a82016-10-03 12:57:33 -07002270/**
2271 * __hdd_wlan_fake_apps_resume() - The core logic for
2272 * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(),
2273 * which is only need for non-irq resume
Dustin Brownbc81a472016-10-26 16:56:59 -07002274 * @wiphy: the kernel wiphy struct for the device being resumed
2275 * @dev: the kernel net_device struct for the device being resumed
Dustin Brownd53d1a82016-10-03 12:57:33 -07002276 *
Dustin Brownbc81a472016-10-26 16:56:59 -07002277 * Return: none, calls QDF_BUG() on failure
Dustin Brownd53d1a82016-10-03 12:57:33 -07002278 */
Dustin Brownbc81a472016-10-26 16:56:59 -07002279static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy,
2280 struct net_device *dev)
Dustin Brownd53d1a82016-10-03 12:57:33 -07002281{
Dustin Brownddb59702017-01-12 16:20:31 -08002282 qdf_device_t qdf_dev;
Dustin Brownd53d1a82016-10-03 12:57:33 -07002283 int i, resume_err;
2284
2285 hdd_info("Unit-test resume WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002286
2287 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2288 if (!qdf_dev) {
2289 hdd_err("Failed to get QDF device context");
2290 QDF_BUG(0);
2291 return;
2292 }
2293
Dustin Brownd53d1a82016-10-03 12:57:33 -07002294 if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
2295 hdd_info("Not unit-test suspended; Nothing to do");
2296 return;
2297 }
2298
2299 /* disable wake irq */
2300 pld_disable_irq(qdf_dev->dev, CE_WAKE_IRQ);
2301
2302 resume_err = wlan_hdd_bus_resume_noirq();
2303 QDF_BUG(resume_err == 0);
2304
2305 /* simulate kernel enable irqs */
2306 for (i = 0; i < CE_IRQ_COUNT; i++)
2307 pld_enable_irq(qdf_dev->dev, i);
2308
2309 resume_err = wlan_hdd_bus_resume();
2310 QDF_BUG(resume_err == 0);
2311
2312 resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy);
2313 QDF_BUG(resume_err == 0);
Dustin Brownbc81a472016-10-26 16:56:59 -07002314
2315 dev->watchdog_timeo = HDD_TX_TIMEOUT;
Dustin Brown562b9672016-12-22 15:25:33 -08002316
2317 hdd_info("Unit-test resume succeeded");
Dustin Brownd53d1a82016-10-03 12:57:33 -07002318}
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002319
2320/**
2321 * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming
2322 * from unit-test initiated suspend from irq wakeup signal
2323 * @val: interrupt val
2324 *
2325 * Resume wlan after getting very 1st CE interrupt from target
2326 *
2327 * Return: none
2328 */
2329static void hdd_wlan_fake_apps_resume_irq_callback(uint32_t val)
2330{
2331 hdd_info("Trigger unit-test resume WLAN; val: 0x%x", val);
2332
2333 QDF_BUG(g_wiphy);
Dustin Brownbc81a472016-10-26 16:56:59 -07002334 QDF_BUG(g_dev);
2335 __hdd_wlan_fake_apps_resume(g_wiphy, g_dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002336 g_wiphy = NULL;
Dustin Brownbc81a472016-10-26 16:56:59 -07002337 g_dev = NULL;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002338}
2339
Dustin Brown54096432017-02-23 13:00:44 -08002340int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev,
2341 enum wow_interface_pause pause_setting,
2342 enum wow_resume_trigger resume_setting)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002343{
Dustin Brownddb59702017-01-12 16:20:31 -08002344 qdf_device_t qdf_dev;
2345 struct hif_opaque_softc *hif_ctx;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002346 pm_message_t state;
2347 int i, resume_err, suspend_err;
Dustin Brown54096432017-02-23 13:00:44 -08002348 struct wow_enable_params wow_params = {
2349 .is_unit_test = true,
2350 .interface_pause = pause_setting,
2351 .resume_trigger = resume_setting
2352 };
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002353
2354 hdd_info("Unit-test suspend WLAN");
Dustin Brownddb59702017-01-12 16:20:31 -08002355
Dustin Brown54096432017-02-23 13:00:44 -08002356 if (pause_setting < WOW_INTERFACE_PAUSE_DEFAULT ||
2357 pause_setting >= WOW_INTERFACE_PAUSE_COUNT) {
2358 hdd_err("Invalid interface pause %d (expected range [0, 2])",
2359 pause_setting);
2360 return -EINVAL;
2361 }
2362
2363 if (resume_setting < WOW_RESUME_TRIGGER_DEFAULT ||
2364 resume_setting >= WOW_RESUME_TRIGGER_COUNT) {
2365 hdd_err("Invalid resume trigger %d (expected range [0, 2])",
2366 resume_setting);
2367 return -EINVAL;
2368 }
2369
Dustin Brownddb59702017-01-12 16:20:31 -08002370 qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
2371 if (!qdf_dev) {
2372 hdd_err("Failed to get QDF device context");
2373 return -EINVAL;
2374 }
2375
2376 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2377 if (!hif_ctx) {
2378 hdd_err("Failed to get HIF context");
2379 return -EINVAL;
2380 }
2381
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002382 if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
2383 hdd_info("Already unit-test suspended; Nothing to do");
2384 return 0;
2385 }
2386
2387 suspend_err = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL);
2388 if (suspend_err)
2389 goto resume_done;
2390
2391 state.event = PM_EVENT_SUSPEND;
Dustin Brown54096432017-02-23 13:00:44 -08002392 suspend_err = wlan_hdd_unit_test_bus_suspend(state, wow_params);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002393 if (suspend_err)
2394 goto cfg80211_resume;
2395
2396 /* simulate kernel disabling irqs */
2397 for (i = 0; i < CE_IRQ_COUNT; i++)
2398 pld_disable_irq(qdf_dev->dev, i);
2399
2400 suspend_err = wlan_hdd_bus_suspend_noirq();
2401 if (suspend_err)
2402 goto enable_irqs_and_bus_resume;
2403
2404 /* re-enable wake irq */
2405 pld_enable_irq(qdf_dev->dev, CE_WAKE_IRQ);
2406
Dustin Brownbc81a472016-10-26 16:56:59 -07002407 /* pass wiphy/dev to callback via global variables */
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002408 g_wiphy = wiphy;
Dustin Brownbc81a472016-10-26 16:56:59 -07002409 g_dev = dev;
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002410 hif_fake_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback);
2411
Dustin Brownbc81a472016-10-26 16:56:59 -07002412 /*
2413 * Tell the kernel not to worry if TX queues aren't moving. This is
2414 * expected since we are suspending the wifi hardware, but not APPS
2415 */
2416 dev->watchdog_timeo = INT_MAX;
2417
Dustin Brown562b9672016-12-22 15:25:33 -08002418 hdd_info("Unit-test suspend succeeded");
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002419 return 0;
2420
2421enable_irqs_and_bus_resume:
2422 /* re-enable irqs */
2423 for (i = 0; i < CE_IRQ_COUNT; i++)
2424 pld_enable_irq(qdf_dev->dev, i);
2425
2426 resume_err = wlan_hdd_bus_resume();
2427 QDF_BUG(resume_err == 0);
2428
2429cfg80211_resume:
2430 resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy);
2431 QDF_BUG(resume_err == 0);
2432
2433resume_done:
2434 clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state);
2435 hdd_err("Unit-test suspend failed: %d", suspend_err);
2436 return suspend_err;
2437}
2438
Dustin Brownbc81a472016-10-26 16:56:59 -07002439int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev)
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002440{
Dustin Brownddb59702017-01-12 16:20:31 -08002441 struct hif_opaque_softc *hif_ctx;
2442
2443 hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2444 if (!hif_ctx) {
2445 hdd_err("Failed to get HIF context");
2446 return -EINVAL;
2447 }
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002448
2449 hif_fake_apps_resume(hif_ctx);
Dustin Brownbc81a472016-10-26 16:56:59 -07002450 __hdd_wlan_fake_apps_resume(wiphy, dev);
Rajeev Kumar9bb2e852016-09-24 12:29:25 -07002451
2452 return 0;
2453}
2454#endif